您的位置:首页 > 其它

3531: [Sdoi2014]旅行

2016-11-01 20:10 253 查看

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
[2],va
,fa
,pfa
,sum
,Max
,rev
,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 DMC
freopen("DMC.txt","r",stdin);
#endif

Read(); 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: