[SDOI2014]旅行
题目描述
S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。
为了方便,我们用不同的正整数代表各种宗教, S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
“CC x c“:城市x的居民全体改信了c教;
“CW x w“:城市x的评级调整为w;
“QS x y“:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
“QM x y“:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
输入输出格式
输入格式:
输入的第一行包含整数N,Q依次表示城市数和事件数。 接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的评级和信仰。 接下来N-1行每行两个整数x,y表示一条双向道路。 接下来Q行,每行一个操作,格式如上所述。
输出格式:
对每个QS和QM事件,输出一行,表示旅行者记下的数字。
输入输出样例
5 6 3 1 2 3 1 2 3 3 5 1 1 2 1 3 3 4 3 5 QS 1 5 CC 3 1 QS 1 5 CW 3 3 QS 1 5 QM 2 4
8 9 11 3
题解:
这道题,乍一看,树链剖分+线段树?呸,明明是两个DFS+伪主席树(不要问我伪主席树是什么,我自己YY的)
实际上就是树剖一下,然后对每一个信仰都开一个线段树,显然空间容不下,那么我们就参照一下主席树节省空间的方式,每次插入一个值就相当于增加一条链(具体看代码)。
因为这里的每一个根节点并没有保存一种状态,所以个人认为应该不是主席树。于是乎就YY了一个伪主席树。
1 //Never forget why you start 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<algorithm> 8 #define ll(x) seg[x].l 9 #define rr(x) seg[x].r 10 using namespace std; 11 int n,m; 12 struct point{ 13 int x,c; 14 }a[150005]; 15 struct node{ 16 int next,to; 17 }edge[300005]; 18 int head[150005],size; 19 void putin(int from,int to){ 20 size++; 21 edge[size].next=head[from]; 22 edge[size].to=to; 23 head[from]=size; 24 } 25 int fa[150005],depth[150005],cnt[150005],son[150005],pos[150005],top[150005],dfscnt; 26 void dfs1(int r,int father){ 27 int i; 28 fa[r]=father; 29 depth[r]=depth[father]+1; 30 cnt[r]++; 31 for(i=head[r];i!=-1;i=edge[i].next){ 32 int y=edge[i].to; 33 if(y!=father){ 34 dfs1(y,r); 35 cnt[r]+=cnt[y]; 36 if(son[r]==-1||cnt[son[r]]<cnt[y])son[r]=y; 37 } 38 } 39 } 40 void dfs2(int r,int tmp){ 41 int i; 42 pos[r]=++dfscnt; 43 top[r]=tmp; 44 if(son[r]!=-1)dfs2(son[r],tmp); 45 for(i=head[r];i!=-1;i=edge[i].next){ 46 int y=edge[i].to; 47 if(y!=fa[r]&&y!=son[r]) 48 dfs2(y,y); 49 } 50 } 51 int root[150005],tot; 52 struct Seg{ 53 int l,r,sum,mmax; 54 friend Seg operator + (const Seg a,const Seg b){ 55 Seg ans; 56 ans.sum=ans.mmax=0; 57 ans.mmax=max(a.mmax,b.mmax); 58 ans.sum=a.sum+b.sum; 59 return ans; 60 } 61 }seg[10000005],zero; 62 void push_up(int root){ 63 seg[root].sum=seg[ll(root)].sum+seg[rr(root)].sum; 64 seg[root].mmax=max(seg[ll(root)].mmax,seg[rr(root)].mmax); 65 } 66 void insert(int &root,int left,int right,int x,int v){ 67 if(root==0)root=++tot; 68 if(left==right){ 69 seg[root].sum=seg[root].mmax=v; 70 return; 71 } 72 int mid=(left+right)>>1; 73 if(x<=mid)insert(ll(root),left,mid,x,v); 74 else insert(rr(root),mid+1,right,x,v); 75 push_up(root); 76 } 77 Seg query(int root,int left,int right,int l,int r){ 78 if(!root)return zero; 79 if(l<=left&&right<=r){ 80 return seg[root]; 81 } 82 if(l>right||r<left)return zero; 83 int mid=(left+right)>>1; 84 return query(ll(root),left,mid,l,r)+query(rr(root),mid+1,right,l,r); 85 } 86 Seg chain_query(int c,int x,int y){ 87 int f1=top[x],f2=top[y]; 88 Seg ans=zero; 89 while(f1!=f2){ 90 if(depth[f1]<depth[f2])swap(x,y),swap(f1,f2); 91 ans=ans+query(root[c],1,n,pos[f1],pos[x]); 92 x=fa[f1];f1=top[x]; 93 } 94 if(depth[x]>depth[y])swap(x,y); 95 ans=ans+query(root[c],1,n,pos[x],pos[y]); 96 return ans; 97 } 98 void clean(){ 99 memset(head,-1,sizeof(head)); 100 memset(son,-1,sizeof(son)); 101 size=0; 102 } 103 int main(){ 104 int i,j; 105 clean(); 106 scanf("%d%d",&n,&m); 107 for(i=1;i<=n;i++) 108 scanf("%d%d",&a[i].x,&a[i].c); 109 for(i=1;i<n;i++){ 110 int u,v; 111 scanf("%d%d",&u,&v); 112 putin(u,v); 113 putin(v,u); 114 } 115 dfs1(1,1);dfs2(1,1); 116 for(i=1;i<=n;i++) 117 insert(root[a[i].c],1,n,pos[i],a[i].x); 118 for(i=1;i<=m;i++){ 119 int u,v; 120 char s[3]; 121 scanf("%s%d%d",s,&u,&v); 122 if(s[0]=='C'){ 123 if(s[1]=='C'){ 124 insert(root[a[u].c],1,n,pos[u],0); 125 insert(root[v],1,n,pos[u],a[u].x); 126 a[u].c=v; 127 } 128 else{ 129 insert(root[a[u].c],1,n,pos[u],v); 130 a[u].x=v; 131 } 132 } 133 else{ 134 Seg ans=chain_query(a[u].c,u,v); 135 if(s[1]=='S')printf("%d\n",ans.sum); 136 else printf("%d\n",ans.mmax); 137 } 138 } 139 return 0; 140 }