BZOJ3531:[SDOI2014]旅行(树链剖分)

Description

 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,并记下了途中留宿过
的城市的评级最大值。
    由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。    为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

Input

    输入的第一行包含整数N,Q依次表示城市数和事件数。
    接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
    接下来N-1行每行两个整数x,y表示一条双向道路。
    接下来Q行,每行一个操作,格式如上所述。

Output

    对每个QS和QM事件,输出一行,表示旅行者记下的数字。

Sample Input

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

Sample Output

8
9
11
3

HINT

N,Q < =10^5    , C < =10^5

数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时
刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。

Solution

因为板子是抄的另一个题的所以细节没改全WA了两次才过QAQ
对于这个题我们第一反应就是:诶这不是裸的树链剖分……

等等好像不太对
这个每次询问只统计链上和起点终点同类的人
那样的话我们对于每一种搞一个链剖就好……

等等好像还是不太对
空间开不开啊QAQ
那咱就线段树动态开点好了。
分析一波复杂度:需要动态开点的只有我代码里的update函数,每次一update最差情况会新增log个节点
那样的话空间就是NlogN的了。
搞定

Code 

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #define N (2000000+100)
  5 using namespace std;
  6 
  7 struct segt{int val,add,max,ls,rs;}Segt[N<<2],refun[N];
  8 struct node{int to,next;}edge[N<<1];
  9 int n,m,a[N],u,v,l,ans,w[N],c[N],Root[N],x,y;
 10 int head[N],num_edge;
 11 int Father[N],Depth[N],Son[N],Sum[N];
 12 int T_num[N],Tree[N],Top[N],dfs_num,segt_num;
 13 char opt[5];
 14 
 15 void add(int u,int v)
 16 {
 17     edge[++num_edge].to=v;
 18     edge[num_edge].next=head[u];
 19     head[u]=num_edge;
 20 }
 21 
 22 void Dfs1(int x) 
 23 {
 24     Sum[x]=1;
 25     Depth[x]=Depth[Father[x]]+1;
 26     for (int i=head[x]; i; i=edge[i].next)
 27         if (edge[i].to!=Father[x])
 28         {
 29             Father[edge[i].to]=x;
 30             Dfs1(edge[i].to);
 31             Sum[x]+=Sum[edge[i].to];
 32             if (!Son[x] || Sum[Son[x]]<Sum[edge[i].to])
 33                 Son[x]=edge[i].to;
 34         }
 35 }
 36 
 37 void Dfs2(int x,int pre)
 38 {
 39     T_num[x]=++dfs_num;
 40     Tree[dfs_num]=a[x];
 41     Top[x]=pre;
 42     if (Son[x]) Dfs2(Son[x],pre);
 43     for (int i=head[x]; i; i=edge[i].next)
 44         if (edge[i].to!=Father[x] && edge[i].to!=Son[x])
 45             Dfs2(edge[i].to,edge[i].to);
 46 }
 47 
 48 void Pushup(int now)
 49 {
 50     Segt[now].val=Segt[Segt[now].ls].val+Segt[Segt[now].rs].val;
 51     Segt[now].max=max(Segt[Segt[now].ls].max,Segt[Segt[now].rs].max);
 52 }
 53 
 54 void Update(int &now,int l,int r,int x,int k) 
 55 {
 56     if (!now) now=++segt_num;
 57     if (l==r)
 58     {
 59         Segt[now].val=k;
 60         Segt[now].max=k;
 61         return;
 62     }
 63     int mid=(l+r)>>1;
 64     if (x<=mid) Update(Segt[now].ls,l,mid,x,k);
 65     else Update(Segt[now].rs,mid+1,r,x,k);
 66     Pushup(now);
 67 }
 68 
 69 int Query_Sum(int now,int l,int r,int l1,int r1)
 70 {
 71     if (now==0) return 0;
 72     if (l>r1 || r<l1) return 0;
 73     if (l1<=l && r<=r1)
 74         return Segt[now].val;
 75     int mid=(l+r)>>1;
 76     if (r1<=mid) return Query_Sum(Segt[now].ls,l,mid,l1,r1);
 77     if (l1>=mid+1) return Query_Sum(Segt[now].rs,mid+1,r,l1,r1);
 78     return Query_Sum(Segt[now].ls,l,mid,l1,r1)+Query_Sum(Segt[now].rs,mid+1,r,l1,r1);
 79 }
 80 
 81 int Query_Max(int now,int l,int r,int l1,int r1)
 82 {
 83     if (now==0) return -1;
 84     if (l>r1 || r<l1) return -1;
 85     if (l1<=l && r<=r1)
 86         return Segt[now].max;
 87     int mid=(l+r)>>1;
 88     if (r1<=mid) return Query_Max(Segt[now].ls,l,mid,l1,r1);
 89     if (l1>=mid+1) return Query_Max(Segt[now].rs,mid+1,r,l1,r1);
 90     return max(Query_Max(Segt[now].ls,l,mid,l1,r1),Query_Max(Segt[now].rs,mid+1,r,l1,r1));
 91 }
 92 
 93 int Ask_Sum(int x,int y)
 94 {
 95     int fx=Top[x],fy=Top[y],r=c[x],ans=0;
 96     while (fx!=fy)
 97     {
 98         if (Depth[fx]<Depth[fy])
 99             swap(x,y),swap(fx,fy);
100         ans+=Query_Sum(Root[r],1,n,T_num[fx],T_num[x]);
101         x=Father[fx],fx=Top[x];
102     }
103     if (Depth[x]<Depth[y]) swap(x,y);
104     ans+=Query_Sum(Root[r],1,n,T_num[y],T_num[x]);
105     return ans; 
106 }
107 
108 int Ask_Max(int x,int y)
109 {
110     int fx=Top[x],fy=Top[y],r=c[x],ans=0;
111     while (fx!=fy)
112     {
113         if (Depth[fx]<Depth[fy])
114             swap(x,y),swap(fx,fy);
115         ans=max(ans,Query_Max(Root[r],1,n,T_num[fx],T_num[x]));
116         x=Father[fx],fx=Top[x];
117     }
118     if (Depth[x]<Depth[y]) swap(x,y);
119     ans=max(ans,Query_Max(Root[r],1,n,T_num[y],T_num[x]));
120     return ans; 
121 }
122 
123 int main()
124 {
125     scanf("%d%d",&n,&m);
126     for (int i=1; i<=n; ++i)
127         scanf("%d%d",&w[i],&c[i]);
128     for (int i=1; i<=n-1; ++i)
129     {
130         scanf("%d%d",&u,&v);
131         add(u,v); add(v,u);
132     }
133     Dfs1(1); Dfs2(1,1);
134     for (int i=1; i<=n; ++i)
135         Update(Root[c[i]],1,n,T_num[i],w[i]);
136         
137     for (int i=1; i<=m; ++i)
138     {
139         scanf("%s%d%d",opt,&x,&y);
140         if (opt[0]=='C' && opt[1]=='C')
141         {
142             Update(Root[c[x]],1,n,T_num[x],0);
143             c[x]=y;
144             Update(Root[c[x]],1,n,T_num[x],w[x]);
145         }
146         if (opt[0]=='C' && opt[1]=='W')
147         {
148             w[x]=y;
149             Update(Root[c[x]],1,n,T_num[x],w[x]);
150         }
151         if (opt[0]=='Q' && opt[1]=='S')
152             printf("%d\n",Ask_Sum(x,y));
153         if (opt[0]=='Q' && opt[1]=='M')
154             printf("%d\n",Ask_Max(x,y));
155     }        
156 }

 

posted @ 2018-05-04 08:45  Refun  阅读(208)  评论(0编辑  收藏  举报