题解:树链剖分细节题 口胡一下LCT也是可以的 只要维护一段的左右两个端点的颜色和长度合并即可
树剖版本(入门的时候写的 好丑啊TAT)
#include<iostream> #include<algorithm> #include<queue> #include<stack> #include<vector> #include<map> #include<set> #include<cstring> #include<cstdio> #define N 200005 using namespace std; vector<int>vec[N]; int pos; int son[N]; int s[N]; int n,m; void inte() { pos=0; for(int i=1; i<=n; i++) son[i]=-1; return ; } int fa[N]; int num[N]; int deep[N]; void dfs(int v,int pre,int w) { fa[v]=pre; num[v]=1; deep[v]=w; for(int i=0; i<vec[v].size(); i++) { int e=vec[v][i]; if(e!=pre) { dfs(e,v,w+1); num[v]+=num[e]; if(son[v]==-1||num[son[v]]<num[e]) { son[v]=e; } } } } int tp[N]; int p[N]; int fp[N]; void biaohao(int v,int sd) { tp[v]=sd; p[v]=++pos; fp[p[v]]=v; if(son[v]==-1) return ; biaohao(son[v],sd); for(int i=0; i<vec[v].size(); i++) { int e=vec[v][i]; if(e!=fa[v]&&e!=son[v]) biaohao(e,e); } } typedef struct node { int first; int end; int l; int r; int flag; int date; } node; node a[4*N]; void built(int root,int first,int end) { if(first==end) { a[root].first=first; a[root].end=end; a[root].l=s[fp[first]]; a[root].r=s[fp[first]]; a[root].flag=-1; a[root].date=1; //cout<<first<<" "<<a[root].l<<" "<<a[root].date<<endl; return ; } int mid=(first+end)/2; built(root*2,first,mid); built(root*2+1,mid+1,end); a[root].first=a[root*2].first; a[root].end=a[root*2+1].end; a[root].l=a[root*2].l; a[root].r=a[root*2+1].r; a[root].flag=-1; if(a[root*2].r==a[root*2+1].l) a[root].date=a[root*2].date+a[root*2+1].date-1; else a[root].date=a[root*2].date+a[root*2+1].date; // cout<<a[root].l<<" "<<a[root].r<<" "<<a[root].date<<endl; } void U(int root,int first,int end,int l,int r,int e) { if(p[l]<=first&&end<=p[r]) { a[root].flag=-1; a[root].l=e; a[root].r=e; a[root].date=1; a[root*2].l=e; a[root*2].r=e; a[root*2].date=1; a[root*2+1].l=e; a[root*2+1].r=e; a[root*2+1].date=1; a[root*2].flag=e; a[root*2+1].flag=e; // cout<<a[root].l<<" "<<a[root].r<<" "<<a[root].date<<endl; return ; } if(a[root].flag!=-1) { a[root*2].l=a[root].flag; a[root*2].r=a[root].flag; a[root*2].date=1; a[root*2+1].l=a[root].flag; a[root*2+1].r=a[root].flag; a[root*2+1].date=1; a[root*2].flag=a[root].flag; a[root*2+1].flag=a[root].flag; a[root].flag=-1; } int mid=(first+end)/2; if(p[l]<=mid) U(root*2,first,mid,l,r,e); if(p[r]>mid) U(root*2+1,mid+1,end,l,r,e); a[root].l=a[root*2].l; a[root].r=a[root*2+1].r; if(a[root*2].r==a[root*2+1].l) a[root].date=a[root*2].date+a[root*2+1].date-1; else a[root].date=a[root*2].date+a[root*2+1].date; } int sum; int p1; int p2; int c1; int c2; int jump; int c3; int cc1; void Q(int root,int first,int end,int l,int r) { if(a[root].flag!=-1) { a[root*2].l=a[root].flag; a[root*2].r=a[root].flag; a[root*2].date=1; a[root*2+1].l=a[root].flag; a[root*2+1].r=a[root].flag; a[root*2+1].date=1; a[root*2].flag=a[root].flag; a[root*2+1].flag=a[root].flag; a[root].flag=-1; } if(p[l]==first){ if(jump==0) p1=a[root].l; else c3=a[root].l; } if(end==p[r]){ if(jump==0) p2=a[root].r; else p1=a[root].r; } if(p[l]<=first&&end<=p[r]) { sum+=a[root].date; return ; } int mid=(first+end)/2; if(p[l]<=mid) Q(root*2,first,mid,l,r); if(p[r]>mid) Q(root*2+1,mid+1,end,l,r); if(p[l]<=mid&&mid<p[r]) sum-=(a[root*2].r==a[root*2+1].l); a[root].l=a[root*2].l; a[root].r=a[root*2+1].r; if(a[root*2].r==a[root*2+1].l) a[root].date=a[root*2].date+a[root*2+1].date-1; else a[root].date=a[root*2].date+a[root*2+1].date; } int Sum(int u,int v) { int uu=tp[u]; int vv=tp[v]; sum=0; jump=-1; c1=-1; c2=-1; while(uu!=vv) { if(deep[uu]<deep[vv]) { swap(uu,vv); swap(u,v); swap(c1,c2); } Q(1,1,n,uu,u); sum=sum-(c1==p1); // cout<<"---------------------"<<sum<<endl; c1=c3; u=fa[uu]; uu=tp[u]; } if(deep[u]>deep[v]) { swap(c1,c2); swap(u,v); } jump=0; cc1=-1; Q(1,1,n,u,v); sum=sum-(c1==p1); sum=sum-(c2==p2); return sum; } void Up(int u,int v,int e) { int uu=tp[u]; int vv=tp[v]; while(uu!=vv) { if(deep[uu]<deep[vv]) { swap(uu,vv); swap(u,v); } U(1,1,n,uu,u,e); u=fa[uu]; uu=tp[u]; } if(deep[u]>deep[v]) swap(u,v); U(1,1,n,u,v,e); return ; } int main() { // freopen("1.txt","r",stdin); // freopen("2.txt","w",stdout); scanf("%d%d",&n,&m); inte(); int aa,bb; for(int i=1; i<=n; i++) scanf("%d",&s[i]); for(int i=1; i<n; i++) { scanf("%d%d",&aa,&bb); vec[aa].push_back(bb); vec[bb].push_back(aa); } dfs(1,-1,1); biaohao(1,1); built(1,1,n); char ch; int u,v,e; for(int i=1; i<=m; i++) { scanf(" %c",&ch); if(ch=='C') { scanf("%d%d%d",&u,&v,&e); Up(u,v,e); } else if(ch=='Q') { scanf("%d%d",&u,&v); int t1=Sum(u,v); printf("%d ",t1); } } return 0; }
2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 10354 Solved: 3969
[Submit][Status][Discuss]
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。