3531: [Sdoi2014]旅行

来源:互联网 发布:unity3d简介 编辑:程序博客网 时间:2024/05/22 00:18

3531: [Sdoi2014]旅行

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 1591  Solved: 708
[Submit][Status][Discuss]

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。

Source

Round 1 Day 1

[Submit][Status][Discuss]



树上修改和询问,很容易想到用LCT解决

但是还有一个关键字是宗教,,总不可能每个节点开n个点维护宗教??

建立n棵树,第i棵树是信仰宗教i的全体子孙的信息,,用LCT维护

这当然是开不下的,,,但是,每次实际需要存的节点信息其实不多

因此,开n棵虚树,用LCT维护虚树,复杂度O(nlogn),,

但是,,常数巨大。。。。。。。。卡常卡了老半天。。。

加了两个小优化过的,,

首先,每个原来的点的信息先储存好,这样建树的时候就直接调用点,不用建完树再重新维护

然后,rotate的时候少个maintain,对于当前splay的节点,留到最后maintain一次就行了


虚树的建立都差点忘光了。。。假设要对n个点建立虚树

把这些点按照dfs序排好,相邻点求lca,如果不在当前集合则新增入集合中

再按dfs排好,维护一个栈,集合内所有元素按顺序入栈

如果栈顶是当前点的祖先,当前点直接入栈

否则当前栈顶不断弹出,每次栈顶与栈顶下面的那个点连边,直到栈顶点是当前点的祖先

最后,剩下的栈内元素一一弹出连边即可

#include<iostream>#include<cstdio>#include<queue>#include<vector>#include<bitset>#include<algorithm>#include<cstring>#include<map>#include<stack>#include<set>#include<cmath>#include<ext/pb_ds/priority_queue.hpp>using namespace std;const int maxn = 1E5 + 10;const int N = 4E5 + 10;struct Query{int typ,x,y; Query(){}Query(int typ,int x,int y): typ(typ),x(x),y(y){}}Q[maxn];struct data{int Num,c; data(){} data(int Num,int c): Num(Num),c(c){}bool operator < (const data &b) const {return c < b.c;}};struct d2{int num,dfn; d2(){} d2(int num,int dfn): num(num),dfn(dfn){}bool operator < (const d2 &b) const {return dfn < b.dfn;}};int n,m,cnt,tot,dfs_clock,dfn[maxn],c[maxn],vis[maxn],w[maxn],L[maxn],ch[N][2],va[N],fa[N],pfa[N],sum[N],Max[N],rev[N],F[maxn][20],Name[maxn];vector <int> v[maxn];vector <int> C[maxn];vector <d2> s[maxn];vector <data> g[maxn];stack <int> S;stack <d2> s2;void pushdown(int x){if (rev[x]) {swap(ch[x][0],ch[x][1]);for (int i = 0; i < 2; i++) if (ch[x][i]) rev[ch[x][i]] ^= 1;rev[x] ^= 1;}}void maintain(int x){sum[x] = Max[x] = va[x];for (int i = 0; i < 2; i++) {sum[x] += sum[ch[x][i]];Max[x] = max(Max[x],Max[ch[x][i]]);}}void rotate(int x){int y = fa[x],z = fa[y];int d = ch[y][0] == x?0:1;pfa[x] = pfa[y]; pfa[y] = 0;ch[y][d] = ch[x][d^1]; if (ch[y][d]) fa[ch[y][d]] = y;ch[x][d^1] = y; fa[y] = x;maintain(y); fa[x] = z; if (z) ch[z][ch[z][1] == y] = x;}void splay(int u){for (int z = u; z; z = fa[z]) S.push(z);while (!S.empty()) {pushdown(S.top()); S.pop();}for (int y = fa[u]; y; rotate(u),y = fa[u])if (fa[y])rotate((ch[y][0] == u)^(ch[fa[y]][0] == y)?u:y);maintain(u);}void Access(int x){for (int z = 0; x; z = x,x = pfa[x]) {splay(x);if (ch[x][1]) fa[ch[x][1]] = 0,pfa[ch[x][1]] = x;if (z) fa[z] = x,pfa[z] = 0;ch[x][1] = z; maintain(x);}}void ChangeRoot(int x) {Access(x); splay(x); rev[x] ^= 1;}void Join(int x,int y) {ChangeRoot(x); pfa[x] = y; Access(x); splay(x);}void Dfs(int x,int from){++cnt; dfn[x] = ++dfs_clock;Name[dfs_clock] = x;for (int i = 1; i < 18; i++) F[x][i] = F[F[x][i-1]][i-1];for (int i = 0; i < C[x].size(); i++) {int t = C[x][i];if (vis[t] == cnt) continue;vis[t] = cnt;g[x].push_back(data(++tot,t));s[t].push_back(d2(tot,dfn[x]));if (t == c[x]) va[tot] = w[x];}sort(g[x].begin(),g[x].end());for (int i = 0; i < v[x].size(); i++) {int to = v[x][i];if (to == from) continue;F[to][0] = x; L[to] = L[x] + 1; Dfs(to,x);}}int getint(){char ch = getchar();int ret = 0;while (ch < '0' || '9' < ch) ch = getchar();while ('0' <= ch && ch <= '9')ret = ret*10 + ch - '0',ch = getchar();return ret;}char com[20];int getcom(){scanf("%s",com);if (com[1] == 'C') return 1;if (com[0] == 'C') return 2;if (com[1] == 'S') return 3;return 4;}void Read(){n = getint(); m = getint();for (int i = 1; i <= n; i++) {w[i] = getint(); c[i] = getint();C[i].push_back(c[i]);}for (int i = 1; i < n; i++) {int x = getint(),y = getint();v[x].push_back(y);v[y].push_back(x);}for (int i = 1; i <= m; i++) {int typ = getcom();int x = getint(),y = getint();if (typ == 1) C[x].push_back(y);Q[i] = Query(typ,x,y);}}void Solve(){for (int i = 1; i <= m; i++) {int x = Q[i].x,y = Q[i].y;int n0 = lower_bound(g[x].begin(),g[x].end(),data(0,c[x])) - g[x].begin();data k0 = g[x][n0];if (Q[i].typ == 1) {int n1 = lower_bound(g[x].begin(),g[x].end(),data(0,y)) - g[x].begin();data k1 = g[x][n1];ChangeRoot(k0.Num);va[k0.Num] = 0; maintain(k0.Num);ChangeRoot(k1.Num);va[k1.Num] = w[x]; maintain(k1.Num);c[x] = y;}else if (Q[i].typ == 2) {ChangeRoot(k0.Num);va[k0.Num] = y; maintain(k0.Num);w[x] = y;}else if (Q[i].typ == 3) {int ny = lower_bound(g[y].begin(),g[y].end(),data(0,c[y])) - g[y].begin();data ky = g[y][ny];ChangeRoot(k0.Num); Access(ky.Num); splay(ky.Num);int ans = sum[ch[ky.Num][0]];printf("%d\n",va[ky.Num] + ans);}else {int ny = lower_bound(g[y].begin(),g[y].end(),data(0,c[y])) - g[y].begin();data ky = g[y][ny];ChangeRoot(k0.Num); Access(ky.Num); splay(ky.Num);int ans = Max[ch[ky.Num][0]];printf("%d\n",max(va[ky.Num],ans));}} }int LCA(int p,int q){if (L[p] < L[q]) swap(p,q);int Log; for (Log = 0; L[p] - (1<<Log) > 0; Log++); --Log;for (int j = Log; j >= 0; j--)if (L[p] - (1<<j) >= L[q])p = F[p][j];if (p == q) return p;for (int j = Log; j >= 0; j--)if (F[p][j] != F[q][j])p = F[p][j],q = F[q][j];return F[p][0];}int main(){#ifdef DMCfreopen("DMC.txt","r",stdin);#endifRead(); L[1] = 1; Dfs(1,0);for (int i = 1; i <= 100000; i++)if (s[i].size() > 1) {sort(s[i].begin(),s[i].end());int siz = s[i].size(); ++cnt;for (int j = 0; j < siz - 1; j++) {d2 A = s[i][j],B = s[i][j+1];vis[Name[s[i][j].dfn]] = vis[Name[s[i][j+1].dfn]] = cnt;int lca = LCA(Name[s[i][j].dfn],Name[s[i][j+1].dfn]);if (dfn[lca] != s[i][j].dfn && dfn[lca] != s[i][j+1].dfn && vis[lca] != cnt)s[i].push_back(d2(++tot,dfn[lca])),vis[lca] = cnt;}sort(s[i].begin(),s[i].end()); s2.push(s[i][0]);for (int j = 1; j < s[i].size(); j++) {d2 A = s[i][j];while (!s2.empty()) {d2 B = s2.top();int lca = LCA(Name[A.dfn],Name[B.dfn]);if (dfn[lca] == B.dfn) break;s2.pop(); if (!s2.empty()) Join(B.num,s2.top().num);}s2.push(A);}for (;;) {d2 A = s2.top(); s2.pop();if (s2.empty()) break;Join(A.num,s2.top().num);}}Solve();return 0;}


0 0