由于历史原因,neuq被camp无情拒绝
 不过有一说一dls讲的课确实好。
H. Crystalfly
题目大意:给你一棵树,每个点都有一定数目的蝴蝶,但是当你经过父亲结点时,它的所有儿子结点的蝴蝶就会被惊动,在
    
     
      
       
        
         t
        
        
         i
        
       
       
        (
       
       
        1
       
       
        ≤
       
       
        
         t
        
        
         i
        
       
       
        ≤
       
       
        3
       
       
        )
       
      
      
       t_i(1\leq t_i \leq 3)
      
     
    ti(1≤ti≤3)秒消失,一开始你位于1号结点,问最大能够抓到的蝴蝶数目是多少。
 分析:不难发现一个走到一个父亲结点时,最多可以拿到两个其儿子结点的蝴蝶数目,因为拿个一个结点再回来再去拿另一个此时已经到了三秒时间,而其它儿子结点的蝴蝶全都消失了,因此我们可以以此为状态进行dp。我们可以设
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       f[i][j]
      
     
    f[i][j]表示对于以
    
     
      
       
        i
       
      
      
       i
      
     
    i为根的子树(不包括
    
     
      
       
        i
       
      
      
       i
      
     
    i)中选拿到
    
     
      
       
        j
       
      
      
       j
      
     
    j个子结点蝴蝶捉到蝴蝶的最大数目,那么
 
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        =
       
       
        
         ∑
        
        
         
          f
         
         
          [
         
         
          v
         
         
          ]
         
         
          =
         
         
          i
         
        
       
       
        m
       
       
        a
       
       
        x
       
       
        (
       
       
        f
       
       
        [
       
       
        v
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
       
        ,
       
       
        f
       
       
        [
       
       
        v
       
       
        ]
       
       
        [
       
       
        2
       
       
        ]
       
       
        )
       
       
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
       
        =
       
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        +
       
       
        m
       
       
        a
       
       
        x
       
       
        (
       
       
        v
       
       
        a
       
       
        l
       
       
        [
       
       
        v
       
       
        ]
       
       
        )
       
       
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        2
       
       
        ]
       
       
        =
       
       
        m
       
       
        a
       
       
        x
       
       
        (
       
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        +
       
       
        f
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        −
       
       
        m
       
       
        a
       
       
        x
       
       
         
       
       
        (
       
       
        f
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
       
        ,
       
       
        f
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        ]
       
       
        [
       
       
        2
       
       
        ]
       
       
        )
       
       
        +
       
       
        v
       
       
        a
       
       
        l
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        ]
       
       
        +
       
       
        v
       
       
        a
       
       
        l
       
       
        [
       
       
        
         v
        
        
         2
        
       
       
        ]
       
       
        )
       
       
        (
       
       
        t
       
       
        [
       
       
        
         v
        
        
         2
        
       
       
        ]
       
       
        =
       
       
        3
       
       
        ,
       
       
        
         v
        
        
         1
        
       
       
        ≠
       
       
        
         v
        
        
         2
        
       
       
        )
       
      
      
       f[i][0]=\sum_{f[v]=i} max(f[v][1],f[v][2]) \\ f[i][1]=f[i][0]+max(val[v]) \\ f[i][2]=max(f[i][0]+f[v_1][0]-max~(f[v_1][1],f[v_1][2])+val[v_1]+val[v_2]) (t[v_2]=3,v_1\neq v_2)
      
     
    f[i][0]=∑f[v]=imax(f[v][1],f[v][2])f[i][1]=f[i][0]+max(val[v])f[i][2]=max(f[i][0]+f[v1][0]−max (f[v1][1],f[v1][2])+val[v1]+val[v2])(t[v2]=3,v1=v2)
 对于前两个方程直接统计即可,第三个方程只需维护
    
     
      
       
        f
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        
       
       
        ]
       
       
        [
       
       
        0
       
       
        ]
       
       
        −
       
       
        m
       
       
        a
       
       
        x
       
       
        (
       
       
        f
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
       
        ,
       
       
        f
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        
       
       
        ]
       
       
        [
       
       
        2
       
       
        ]
       
       
        )
       
       
        +
       
       
        v
       
       
        a
       
       
        l
       
       
        [
       
       
        
         v
        
        
         1
        
       
       
        
       
       
        ]
       
      
      
       f[v_1][0]−max(f[v_1][1],f[v_1][2])+val[v_1]
      
     
    f[v1][0]−max(f[v1][1],f[v1][2])+val[v1]的最大值和次大值即可。最后答案即为 
    
     
      
       
        m
       
       
        a
       
       
        x
       
       
        (
       
       
        f
       
       
        [
       
       
        1
       
       
        ]
       
       
        [
       
       
        1
       
       
        ]
       
       
        ,
       
       
        f
       
       
        [
       
       
        1
       
       
        ]
       
       
        [
       
       
        2
       
       
        ]
       
       
        )
       
       
        +
       
       
        v
       
       
        a
       
       
        l
       
       
        [
       
       
        1
       
       
        ]
       
      
      
       max(f[1][1],f[1][2])+val[1]
      
     
    max(f[1][1],f[1][2])+val[1]
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
#define int long long
#define maxn 1000005
using namespace std;
int read()
{
	int x=1,res=0;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')
		x=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		res=res*10+(c-'0');
		c=getchar();
	}
	return res*x;
}
struct edge{
	int next,to;
}g[maxn<<1];
int val[maxn],num,last[maxn],n,t[maxn],f[maxn][3],ma[maxn],aa,bb;
void clean()
{
	for(int i=1;i<=num;i++) last[i]=0,g[i]=(edge){0,0};
	for(int i=1;i<=n;i++) f[i][0]=f[i][1]=f[i][2]=0,ma[i]=0;
	num=0;
}
void add(int from,int to)
{
	g[++num].next=last[from];
	g[num].to=to;
	last[from]=num;
}
void dfs(int x,int fa)
{
	int tot=0,max1=-2e18,max2=-2e18,maxx=0,max1v,max2v,cnt=0;
	for(int i=last[x];i;i=g[i].next)
	{
		int v=g[i].to;
		if(v!=fa) {
			cnt++;dfs(v,x);
			ma[v]=max(f[v][1],f[v][2]);
			tot+=ma[v];maxx=max(maxx,val[v]);
			int c=f[v][0]-ma[v]+val[v];
			if(c>max1){
				max2v=max1v;max2=max1;
				max1v=v;max1=c;
			}
			else if(c>max2) max2v=v,max2=c;
		}
	}
	f[x][0]=tot;f[x][1]=tot+maxx;
	if(cnt<=1) return;
	for(int i=last[x];i;i=g[i].next)
	{
		int v=g[i].to;
		if(v!=fa&&t[v]==3){
			if(v!=max1v)
			f[x][2]=max(f[x][2],tot+max1+val[v]);
			else f[x][2]=max(f[x][2],tot+max2+val[v]);
		}
	}
}
void solve()
{
	clean();n=read();
	for(int i=1;i<=n;i++) val[i]=read();
	for(int i=1;i<=n;i++) t[i]=read();
	for(int i=1;i<n;i++)
	{
		aa=read();bb=read();
		add(aa,bb);add(bb,aa);
	}
	dfs(1,0);
	printf("%lld\n",max(f[1][1],f[1][2])+val[1]);
}
signed main()
{
	int t=read();
	while(t--)
	solve();
}
F. Towers
题目大意:给你一棵树,每个结点都有一个高度
    
     
      
       
        
         h
        
        
         i
        
       
      
      
       h_i
      
     
    hi,要求在一些结点上建塔,塔高为
    
     
      
       
        
         w
        
        
         i
        
       
      
      
       w_i
      
     
    wi,并且使得任意一个结点都存在一条包含该点的简单路径
    
     
      
       
        x
       
       
        −
       
       
        >
       
       
        y
       
      
      
       x->y
      
     
    x−>y使得
    
     
      
       
        w
       
       
        [
       
       
        x
       
       
        ]
       
       
        ,
       
       
        w
       
       
        [
       
       
        y
       
       
        ]
       
       
        ≥
       
       
        h
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       w[x],w[y] \geq h[i]
      
     
    w[x],w[y]≥h[i],求 
    
     
      
       
        ∑
       
       
        w
       
       
        [
       
       
        i
       
       
        ]
       
      
      
       \sum w[i]
      
     
    ∑w[i]的最小值。
 分析:首先对于根结点,我们把高度最高的结点设为根结点,这样我们对于非根结点只需要在其包含自身的子树中找到塔高最高的结点,并将其高度提升到大于等于这个结点的高度,这样对于每个非根结点就一定可以找到一条路径符合题意,对于根节点,只需要求出最大和次大的子树并把其高度分别提升至根节点的高度即可,这样我们对每个子树只需要维护其最高的塔高即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
#define clean(x) memset(x,0,sizeof(x))
#define maxn 1000005
#define int long long
using namespace std;
int read()
{
	int x=1,res=0;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')
		x=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		res=res*10+(c-'0');
		c=getchar();
	}
	return res*x;
}
struct node{
	int next,to;
}g[maxn<<1];
int n,h[maxn],num,aa,bb,maxx,root,last[maxn],f[maxn],sz[maxn],ans,pd,tot1,tot2;
void add(int from,int to)
{
	g[++num].next=last[from];
	g[num].to=to;
	last[from]=num;
}
void dfs(int u,int fa)
{
	sz[u]=1;
	for(int i=last[u];i;i=g[i].next)
	{
		int v=g[i].to;
		if(v!=fa)
		{
			dfs(v,u);
			sz[u]+=sz[v];
			f[u]=max(f[u],f[v]);
			if(u==root){
				if(f[v]>tot1){
					tot2=tot1;
					tot1=f[v];
				}
				else if(f[v]>tot2) tot2=f[v];
			}
		}
	}
	if(u==root)
		ans+=h[u]-tot1+h[u]-tot2;
	else 
		if(f[u]>=h[u]) return;
		else {
			ans+=h[u]-f[u];
			f[u]=h[u];
		}
}
signed main()
{
	n=read();
	for(int i=1;i<=n;i++)
	{
		h[i]=read();
		if(h[i]>=maxx) {
			maxx=h[i];
			root=i;
		}
	}
	for(int i=1;i<n;i++)
	{
		aa=read();bb=read();
		add(aa,bb);add(bb,aa);
	}
	dfs(root,0);
	cout<<ans;
	return 0;
}
C. Paint
题目大意:给定一个序列,每次可以选择其中连续且数值相同的一段并将这一段数值全部变成任意一个数,最少进行多少次操作可以使得序列所有的数值都相同,求这个最小值。
 分析:对于一段连续的区间,如果区间两侧的数相同,那么只需要操作一次即可让左右两个数加上该区间的数全都相同,因此我们可以考虑序列中最多可以找出多少左右配对的区间,因此我们设
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
      
      
       f[i][j]
      
     
    f[i][j]表示区间
    
     
      
       
        [
       
       
        i
       
       
        ,
       
       
        j
       
       
        ]
       
      
      
       [i,j]
      
     
    [i,j]的最大匹配数目,那么
 
    
     
      
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
       
        =
       
       
        f
       
       
        [
       
       
        i
       
       
        +
       
       
        1
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
       
       
        f
       
       
        [
       
       
        i
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
       
        =
       
       
        f
       
       
        [
       
       
        i
       
       
        +
       
       
        1
       
       
        ]
       
       
        [
       
       
        m
       
       
        −
       
       
        1
       
       
        ]
       
       
        +
       
       
        f
       
       
        [
       
       
        m
       
       
        ]
       
       
        [
       
       
        j
       
       
        ]
       
       
        +
       
       
        1
       
       
        (
       
       
        n
       
       
        e
       
       
        x
       
       
        t
       
       
        [
       
       
        a
       
       
        [
       
       
        i
       
       
        ]
       
       
        ]
       
       
        =
       
       
        m
       
       
        )
       
      
      
       f[i][j]=f[i+1][j] \\ f[i][j]=f[i+1][m-1]+f[m][j]+1(next[a[i]]=m)
      
     
    f[i][j]=f[i+1][j]f[i][j]=f[i+1][m−1]+f[m][j]+1(next[a[i]]=m)
 我们只需要记录next[i]的位置即可,由于每个数出现此时不超过20次,时间复杂度为
    
     
      
       
        O
       
       
        (
       
       
        20
       
       
        
         n
        
        
         2
        
       
       
        )
       
      
      
       O(20n^2)
      
     
    O(20n2)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
#define clean(x) memset(x,0,sizeof(x))
#define maxn 5005
using namespace std;
int read()
{
	int x=1,res=0;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')
		x=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		res=res*10+(c-'0');
		c=getchar();
	}
	return res*x;
}
int n,a[maxn],lt[maxn],nt[maxn],f[maxn][maxn];
void solve()
{
	n=read();
	for(int i=1;i<=n;i++) lt[i]=nt[i]=0;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)  
	f[i][j]=0;
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		if(lt[a[i]]==0) lt[a[i]]=i;
		else{
			nt[lt[a[i]]]=i;
			lt[a[i]]=i;
		}
	}
	for(int i=2;i<=n;i++){
		for(int l=1;l<=n-i+1;l++){
			int r=l+i-1;
			f[l][r]=max(f[l][r],f[l+1][r]);
			int k=nt[l];
			while(k&&k<=r){
				f[l][r]=max(f[l][r],f[l+1][k]+f[k][r]+1);
				k=nt[k];
			}
//			cout<<l<<" "<<r<<" "<<f[l][r]<<endl;
		}
	}
	printf("%d\n",n-1-f[1][n]);
}
int main()
{
	int t=read();
	while(t--)
	solve();
	return 0;
}
C. Werewolves
题目大意:给你一棵树,每个点都有一个颜色,对于每一种颜色我们要求出所有的该颜色数目严格多于其它颜色的子树的数目。
 分析:我们在计算某一种颜色之时,我们可以将该颜色的结点权值设为1,非该颜色结点权值设为-1,那么符合条件的子树的数目就是子树权值为正的方案数,这个可以通过树上背包方案数实现,但是问题就是时间复杂度,这样做如果颜色数目很多时间复杂度是
    
     
      
       
        O
       
       
        (
       
       
        
         n
        
        
         3
        
       
       
        )
       
      
      
       O(n^3)
      
     
    O(n3),然而仔细分析一下会发现对于颜色很多的情况,每次背包非该颜色的结点会非常多,而该颜色结点会非常少,假设当前颜色数目为m,那么如果某个状态等于-m时,这个状态就对答案不可能有贡献了,因此我们只需要对区间
    
     
      
       
        [
       
       
        −
       
       
        m
       
       
        ,
       
       
        m
       
       
        ]
       
      
      
       [-m,m]
      
     
    [−m,m]之间的状态进行转移即可,因此时间复杂度为
    
     
      
       
        O
       
       
        (
       
       
        
         n
        
        
         2
        
       
       
        )
       
      
      
       O(n^2)
      
     
    O(n2)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
#define mod 998244353
#define int long long
#define clean(x) memset(x,0,sizeof(x))
#define maxn 3005
using namespace std;
int read()
{
	int x=1,res=0;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')
		x=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		res=res*10+(c-'0');
		c=getchar();
	}
	return res*x;
}
struct edge{
	int next,to;
}g[maxn<<1];
int n,num,last[maxn],aa,bb,ans,val[maxn],sz[maxn],s[maxn<<1],t[maxn<<1],f[maxn][2*maxn+100];
void add(int from,int to)
{
	g[++num].next=last[from];
	g[num].to=to;
	last[from]=num;
}
void dfs(int x,int fa,int va,int m)
{
	int c;sz[x]=1;
	if(val[x]==va) c=1;
	else c=-1;
	f[x][c+m]=1;
	for(int i=last[x];i;i=g[i].next)
	{
		int v=g[i].to;
		if(v!=fa){
			dfs(v,x,va,m);
			sz[x]+=sz[v];
			for(int j=max(-m,-sz[v]);j<=min(m,sz[v]);j++)
			{
				if(f[v][j+m]==0) continue;
				if(j<0) for(int k=max(-m,-sz[x]+sz[v]);k<=min(m,sz[x]-sz[v]);k++)
				{if(k+j<=m&&k+j>=-m) t[k+j+m]=(t[k+j+m]+f[x][k+m]*f[v][j+m])%mod;}
				else for(int k=min(m,sz[x]-sz[v]);k>=max(-m,-sz[x]+sz[v]);k--)
				if(k+j<=m&&k+j>=-m) t[k+j+m]=(t[k+j+m]+f[x][k+m]*f[v][j+m])%mod;
				
			}
			for(int j=-m;j<=m;j++) {
				f[x][j+m]=(f[x][j+m]+t[j+m])%mod;
				t[j+m]=0;f[v][j+m]=0;
			}
		}
	}
	for(int j=1;j<=m;j++) ans=(ans+f[x][j+m])%mod;
}
signed main()
{
//freopen("1.in","r",stdin);
	n=read();
	for(int i=1;i<=n;i++) {
		val[i]=read();
		s[val[i]]++;
	}
	for(int i=1;i<n;i++)
	{
		aa=read();bb=read();
		add(aa,bb);
		add(bb,aa);
	}
	for(int i=1;i<=n;i++){
		if(s[i]==0) continue;
		memset(f[1],0,sizeof(f[1]));
		dfs(1,0,i,s[i]);
	}
	cout<<ans;
	return 0;
}
P4766 [CERC2014]Outer space invaders
题目大意:N个外星人进攻,第 
    
     
      
       
        i
       
      
      
       i
      
     
    i个外星人在时间 
    
     
      
       
        
         a
        
        
         i
        
       
      
      
       a_i
      
     
    ai出现,距离
    
     
      
       
        
         d
        
        
         i
        
       
      
      
       d_i
      
     
    di它必须在时间 
    
     
      
       
        
         b
        
        
         i
        
       
      
      
       b_i
      
     
    bi前被消灭,你可以消灭与你的距离在
    
     
      
       
        R
       
      
      
       R
      
     
    R以内的所有外星人(可以等于),同时它也会消耗
    
     
      
       
        R
       
      
      
       R
      
     
    R单位的燃料电池。求摧毁所有外星人的最低成本(消耗多少燃料电池),同时保证自己的生命安全。
 分析:我们每次都一定要通过一颗最大的炸弹消灭距离最远的外星人,并且可以枚举放置这个炸弹的时间,然后就可以分成左右两个区间再分别进行求解,我们可以用记忆化搜索来实现区间dp,设
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        l
       
       
        ]
       
       
        [
       
       
        r
       
       
        ]
       
      
      
       dp[l][r]
      
     
    dp[l][r]表示在l—r时间打死所有外星人花费的代价
 
    
     
      
       
        d
       
       
        p
       
       
        [
       
       
        l
       
       
        ]
       
       
        [
       
       
        r
       
       
        ]
       
       
        =
       
       
        m
       
       
        i
       
       
        n
       
       
        (
       
       
        d
       
       
        p
       
       
        [
       
       
        l
       
       
        ]
       
       
        [
       
       
        k
       
       
        −
       
       
        1
       
       
        ]
       
       
        +
       
       
        a
       
       
        [
       
       
        i
       
       
        d
       
       
        ]
       
       
        .
       
       
        d
       
       
        +
       
       
        d
       
       
        p
       
       
        [
       
       
        k
       
       
        +
       
       
        1
       
       
        ]
       
       
        [
       
       
        r
       
       
        ]
       
       
        )
       
       
          
       
       
        (
       
       
        k
       
       
        >
       
       
        =
       
       
        a
       
       
        [
       
       
        i
       
       
        d
       
       
        ]
       
       
        .
       
       
        l
       
       
        t
       
       
        ,
       
       
        k
       
       
        <
       
       
        =
       
       
        a
       
       
        [
       
       
        i
       
       
        d
       
       
        ]
       
       
        .
       
       
        r
       
       
        t
       
       
        )
       
      
      
       dp[l][r]=min(dp[l][k-1]+a[id].d+dp[k+1][r]) ~~(k>=a[id].lt,k<=a[id].rt)
      
     
    dp[l][r]=min(dp[l][k−1]+a[id].d+dp[k+1][r])  (k>=a[id].lt,k<=a[id].rt)
 时间复杂度
    
     
      
       
        O
       
       
        (
       
       
        
         n
        
        
         3
        
       
       
        )
       
      
      
       O(n^3)
      
     
    O(n3)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
#define clean(x) memset(x,0,sizeof(x))
#define maxn 605
using namespace std;
int read()
{
	int x=1,res=0;
	char c=getchar();
	while(c<'0'||c>'9')
	{
		if(c=='-')
		x=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9')
	{
		res=res*10+(c-'0');
		c=getchar();
	}
	return res*x;
}
struct node{
	int l,r,h;
}g[maxn];
int n,f[maxn][maxn],cnt,b[maxn*2];
int dfs(int l,int r)
{
	if(l>r) return 0;
	if(f[l][r]!=-1) return f[l][r];
	int mpos=-1,mval=-1;
	for(int i=1;i<=n;i++)
	{
		if(g[i].l<l||g[i].r>r) continue;
		if(g[i].h>mval) mval=g[i].h,mpos=i;
	}
	if(mval==-1) return f[l][r]=0;
	int ans=2e9;
	for(int i=g[mpos].l;i<=g[mpos].r;i++)
	{
		ans=min(ans,dfs(l,i-1)+dfs(i+1,r)+mval);
	}
	f[l][r]=ans;
	return f[l][r];
}
void solve()
{
	n=read();cnt=0;
	memset(f,-1,sizeof f);
	for(int i=1;i<=n;i++)
	{
		g[i].l=read();g[i].r=read();g[i].h=read();
		b[++cnt]=g[i].l;b[++cnt]=g[i].r;
	}
	sort(b+1,b+1+cnt);
	int tott=unique(b+1,b+1+cnt)-b-1;
	for(int i=1;i<=n;i++){
		g[i].l=lower_bound(b+1,b+1+tott,g[i].l)-b;
		g[i].r=lower_bound(b+1,b+1+tott,g[i].r)-b;
//		cout<<g[i].l<<" "<<g[i].r<<endl;
	}
	printf("%d\n",dfs(1,tott));
}
int main()
{
	int t=read();
	while(t--)
	solve();
	return 0;
}










