[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事件,输出一行,表示旅行者记下的数字。

输入输出样例

输入样例#1: 
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
输出样例#1:
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 }

 

posted @ 2018-01-10 19:22  kakakakakaka  阅读(145)  评论(0编辑  收藏  举报

Never forget why you start

//鼠标爆炸特效