bzoj 3531 [Sdoi2014]旅行 (树剖+线段树 动态开点)

3531: [Sdoi2014]旅行

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 2984  Solved: 1312
[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

思路:
对n种信仰建n棵线段树维护,直接写肯定超内存,不过用动态开点就好了。
实现代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define ll long long
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid ll m = (l + r) >> 1
const double EPS = 1e-8;
//inline ll sgn(double x) return (x > EPS) - (x < -EPS); //浮点数比较常数优化写法
const int M = 2e5+10;
int n,q,cnt,cnt1,ne;
struct node{
    int to,next;
}e[M];
const int N = 1e7+10;
int ls[N],rs[N],mx[N],rt[N],wi[M],ci[M];
int sum[N],son[M],fa[M],head[M],siz[M],top[M],dep[M],tid[M],rk[M];
void add(int u,int v){
    e[++cnt1].to = v;e[cnt1].next = head[u];head[u] = cnt1;
    e[++cnt1].to = u;e[cnt1].next = head[v];head[v] = cnt1;
}

void dfs1(int u,int faz,int deep){
     dep[u] = deep;
     fa[u] = faz;
     siz[u] = 1;
     for(int i = head[u];i;i=e[i].next){
        int v = e[i].to;
        if(v != fa[u]){
            dfs1(v,u,deep+1);
            siz[u] += siz[v];
            if(son[u] == -1||siz[v] > siz[son[u]])
                son[u] = v;
        }
     }
}

void dfs2(int u,int t){
    top[u] = t;
    tid[u] = cnt;
    rk[cnt] = u;
    cnt++;
    if(son[u] == -1) return;
    dfs2(son[u],t);
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(v != son[u]&&v != fa[u])
            dfs2(v,v);
    }
}

void pushup(int rt){
    sum[rt] = sum[ls[rt]] + sum[rs[rt]];
    mx[rt] = max(mx[ls[rt]],mx[rs[rt]]);
}

void change(int &k,int l,int r,int p,int num){
    if(!k) k = ++ne;
    if(l == r) {
        mx[k] = sum[k] = num;
        //cout<<k<<" "<<mx[k]<<endl;
        return ;
    }
    mid;
    if(p <= m) change(ls[k],l,m,p,num);
    else change(rs[k],m+1,r,p,num);
    pushup(k);
}

int querym(int k,int L,int R,int l,int r){
    if(!k) return 0;  //防止访问到没被拓展过的点
    if(L <= l&&R >= r){
        return mx[k];
    }
    mid;
    int ret = 0;
    if(L <= m) ret = max(ret,querym(ls[k],L,R,l,m));
    if(R > m) ret = max(ret,querym(rs[k],L,R,m+1,r));
    return ret;
}

int querys(int k,int L,int R,int l,int r){
    if(!k) return 0;
    if(L <= l&&R >= r){
        return sum[k];
    }
    mid;
    int ret = 0;
    if(L <= m) ret += querys(ls[k],L,R,l,m);
    if(R > m) ret += querys(rs[k],L,R,m+1,r);
    return ret;
}

int askm(int x,int y,int c){
    int maxx = 0;
    int fx=top[x],fy=top[y];
    while(fx!=fy){
        if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
        maxx = max(maxx,querym(rt[c],tid[fx],tid[x],1,n));
        x = fa[fx]; fx = top[x];
    }
    if(dep[x] > dep[y]) swap(x,y);
    maxx = max(maxx,querym(rt[c],tid[x],tid[y],1,n));
    return maxx;
}

int asks(int x,int y,int c){
    int ans = 0;
    int fx = top[x],fy = top[y];
    while(fx != fy){
        if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
        ans += querys(rt[c],tid[fx],tid[x],1,n);
        x = fa[fx]; fx = top[x];
    }
    if(dep[x] > dep[y]) swap(x,y);
    ans += querys(rt[c],tid[x],tid[y],1,n);
    return ans;
}

int main()
{
    cin>>n>>q;
    memset(son,-1,sizeof(son));
    cnt1 = 0; cnt = 1; ne = 0;
    for(int i = 1;i <= n;i ++){
        cin>>wi[i]>>ci[i];
    }
    int u,v,x,y;
    for(int i = 1;i < n;i ++){
        cin>>u>>v;
        add(u,v);
    }
    dfs1(1,0,1); dfs2(1,1);
    for(int i = 1;i <= n;i ++){
        change(rt[ci[i]],1,n,tid[i],wi[i]);
    }
    string s;
    while(q--){
        cin>>s;
        cin>>x>>y;
        if(s[0]=='C'){
            if(s[1]=='C'){
                change(rt[ci[x]],1,n,tid[x],0);
                ci[x] = y;
                change(rt[ci[x]],1,n,tid[x],wi[x]);
            }
            else change(rt[ci[x]],1,n,tid[x],y),wi[x] = y;
        }
        else{
            if(s[1] == 'S') cout<<asks(x,y,ci[x])<<endl;
            else cout<<askm(x,y,ci[x])<<endl;
        }
    }
    return 0;
}

 

posted @ 2018-05-02 21:54  冥想选手  阅读(174)  评论(0编辑  收藏  举报