「luogu3313」[SDOI2014] 旅行

题目大意 :
有 n 个城市连成一棵树, 每个城市有两个关键字, 一个是该城市的宗教, 另一个是城市的评级;
旅行者要在城市间旅行, 他只会在和自己宗教相同的城市留宿;
维护四个树上操作 {
1. “CC x c“ :城市 x 的居民全体改信了 c 教;
2. “CW x w“ :城市 x 的评级调整为 w;
3. “QS x y“ :一位旅行者从城市 x 出发,到城市 y,并记下了途中留宿过的城市的评级总和;
4. “QM x y“:一位旅行者从城市 x 出发,到城市 y ,并记下了途中留宿过的城市的评级最大值;
}
(旅行者信的教和旅行的终点相同;

树剖+线段树 : 如果对每种宗教都开一颗线段树, 内存爆炸 -------> 考虑动态开点

动态开点 {
在这道题中, 可以考虑给每一种宗教开一个线段树, 但一开始不需要开满;
对于每一个第一次出现的宗教或者一个宗教里的一个新城市, 都把他当做一个新节点;
对于单次操作 时间复杂度和空间复杂度都是 O(log n) , 因为对于一种宗教最多有n个节点, 在线段树里找到一个节点最多 logn+1 次;
}

代码如下 :

  1 //Author : 15owzLy1
  2 //luogu3313.cpp
  3 //2018 12 09      14:24:30
  4 #include <iostream>
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <algorithm>
  8 #define INF 2100000000
  9 typedef long long ll;
 10 typedef double db;
 11 template<typename T>inline void read(T &_) {
 12     _=0;int __=0;char ___=getchar();
 13     while(___<'0'||___>'9')__|=(___=='-'),___=getchar();
 14     while(___>='0'&&___<='9')_=(_<<1)+(_<<3)+(___^48),___=getchar();
 15     _=__?-_:_;
 16 }
 17 
 18 const int N = (int)1e5+5;
 19 struct edge {
 20     int next, to;
 21 }edge[N<<1];
 22 int head[N], cnt=1, c[N], w[N];
 23 int n, q, hson[N], size[N], dfn[N], front[N], dep[N], fa[N];
 24 
 25 class Segment_Tree {
 26 private :
 27     struct node {
 28         int sum, max, l, r;
 29         #define t a[rt]
 30         #define lson a[a[rt].l]
 31         #define rson a[a[rt].r]
 32     }a[N*20];
 33     int cnt;
 34     inline void push_up(int rt) {
 35         t.sum=lson.sum+rson.sum;
 36         t.max=std::max(lson.max, rson.max);
 37     }
 38 public :
 39     int root[N];
 40     void update(int &rt, int del, int tl, int tr, int pos) {
 41         if(!rt) rt=++cnt;
 42         if(tl==tr) { t.max=t.sum=del; return ; }
 43         int mid=(tl+tr)>>1;
 44         if(mid>=pos) update(t.l, del, tl, mid, pos);
 45         else         update(t.r, del, mid+1, tr, pos);
 46         push_up(rt);
 47     }
 48     void remove(int &rt, int tl, int tr, int pos) {
 49         if(tl==tr) { rt=t.sum=t.max=0; return ; }
 50         int mid=(tl+tr)>>1;
 51         if(mid>=pos) remove(t.l, tl, mid, pos);
 52         else         remove(t.r, mid+1, tr, pos);
 53         push_up(rt);
 54     }
 55     int query_sum(int rt, int l, int r, int tl, int tr) {
 56         if(l<=tl&&tr<=r) return t.sum;
 57         int mid=(tl+tr)>>1, ret=0;
 58         if(mid>=l) ret+=query_sum(t.l, l, r, tl, mid);
 59         if(mid<r)  ret+=query_sum(t.r, l, r, mid+1, tr);
 60         return ret;
 61     }
 62     int query_max(int rt, int l, int r, int tl, int tr) {
 63         if(l<=tl&&tr<=r) return t.max;
 64         int mid=(tl+tr)>>1, ret=0;
 65         if(mid>=l) ret=std::max(ret, query_max(t.l, l, r, tl, mid));
 66         if(mid<r)  ret=std::max(ret, query_max(t.r, l, r, mid+1, tr));
 67         return ret;
 68     }
 69 }T;
 70 
 71 inline void jb(int u, int v) {
 72     edge[++cnt].to=v;
 73     edge[cnt].next=head[u];
 74     head[u]=cnt;
 75 }
 76 
 77 void get_hson(int u) {
 78     size[u]=1;
 79     for(int i=head[u];i;i=edge[i].next) {
 80         int v=edge[i].to;
 81         if(v==fa[u]) continue;
 82         fa[v]=u, dep[v]=dep[u]+1;
 83         get_hson(v);
 84         size[u]+=size[v];
 85         if(size[v]>=size[hson[u]]) hson[u]=v;
 86     }
 87 }    
 88 
 89 void get_front(int u, int father) {
 90     dfn[u]=++dfn[0], front[u]=father;
 91     if(hson[u]) get_front(hson[u], father);
 92     for(int i=head[u];i;i=edge[i].next) {
 93         int v=edge[i].to;
 94         if(v==fa[u]||v==hson[u]) continue;
 95         get_front(v, v);
 96     }
 97 }
 98 
 99 inline int query_sum(int u, int v) {
100     int ret=0, cl=c[v];
101     while(front[u]!=front[v]) {
102         if(dep[front[u]]>dep[front[v]]) std::swap(u, v);
103         ret+=T.query_sum(T.root[cl], dfn[front[v]], dfn[v], 1, n);
104         v=fa[front[v]];
105     }
106     if(dep[u]>dep[v]) std::swap(u, v);
107     ret+=T.query_sum(T.root[cl], dfn[u], dfn[v], 1, n);
108     return ret;
109 }
110 
111 inline int query_max(int u, int v) {
112     int ret=0, cl=c[v];
113     while(front[u]!=front[v]) {
114         if(dep[front[u]]>dep[front[v]]) std::swap(u, v);
115         ret=std::max(ret, T.query_max(T.root[cl], dfn[front[v]], dfn[v], 1, n));
116         v=fa[front[v]];
117     }
118     if(dep[u]>dep[v]) std::swap(u, v);
119     ret=std::max(ret, T.query_max(T.root[cl], dfn[u], dfn[v], 1, n));
120     return ret;
121 }
122 
123 int main() {
124 #ifndef ONLINE_JUDGE
125     freopen("luogu3313.in","r",stdin);
126     freopen("luogu3313.out","w",stdout);
127 #endif
128     char opt[3];
129     int x, y;
130     read(n), read(q);
131     for(int i=1;i<=n;i++) read(w[i]), read(c[i]);
132     for(int i=1;i<n;i++) read(x), read(y), jb(x, y), jb(y, x);
133     get_hson(1); get_front(1, 1);
134     for(int i=1;i<=n;i++)
135         T.update(T.root[c[i]], w[i], 1, n, dfn[i]);
136 
137     while(q--) {
138         scanf("%s", opt);
139         read(x), read(y);
140         if(opt[0]=='C') {
141             //change C    change W
142             if(opt[1]=='C') {
143                 T.remove(T.root[c[x]], 1, n, dfn[x]);
144                 c[x]=y;
145                 T.update(T.root[c[x]], w[x], 1, n, dfn[x]);
146             }
147             else T.update(T.root[c[x]], y, 1, n, dfn[x]), w[x]=y;
148         }
149         else {
150             //query S     query W
151             if(opt[1]=='S')    printf("%d\n", query_sum(x, y));
152             else            printf("%d\n", query_max(x, y));
153         }
154     }
155     return 0;
156 }
View Code

 

posted @ 2018-12-09 21:11  15owzLy1  阅读(176)  评论(0编辑  收藏  举报