ustc 1303 Special tree

http://acm.ustc.edu.cn/ustcoj/problem.php?id=1303
/*
题意:给一棵树,树上每个节点都有一个值。对于一棵树,如果断开某一条边,就会形成两个连通分量。现有两种操作:
Query x:如果断开第x条边,输出两个连通分量里的最大值,值小的在前面。
Add x a b:如果断开第x条边形成的两个连通分量里节点的个数不相等,则节点多的连通分量里都加上max(a,b),节点少的连通分量里都加上min(a,b).

思路:原题是这个吧:http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1333
dfs遍历一次树,就可以得到一个序列,也就得到每个节点管理的区间。
用线段树维护每个节点下的最大值和最小值就行了,区间更新。
*/

View Code
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
const int maxn = 10005;
struct nd{int next,v;}edge[maxn*2];
struct nnd{int s,tp,c,mx,mn;}as[maxn*4];
int head[maxn],vis[maxn],ls[maxn][2];
int val[maxn],E[maxn][2];
int n,m,ecnt,idx;
inline int min(int x,int y){return x > y ? y : x;}
inline int max(int x,int y){return x > y ? x : y;}
void add(int u,int v)
{
    edge[ecnt].v = v;
    edge[ecnt].next = head[u];
    head[u] = ecnt++;
}
int getlist(int pre,int x)
{
    vis[++idx] = x;
    ls[x][0] = ls[x][1] = idx;//x节点的管理的区间为[ ls[x][0],ls[x][1] ]。
    for(int i = head[x]; ~i; i = edge[i].next){
        if(edge[i].v==pre)continue;
        ls[x][1]=getlist(x,edge[i].v);
    }
    return ls[x][1];
}
void readin()
{
    int i;
    scanf("%d %d",&n,&m);
    for(i = 1; i <= n; ++ i)
    scanf("%d",val+i);

    ecnt = 0;
    memset(head,-1,sizeof(head));
    for(i = 1; i < n; ++ i){
        scanf("%d %d",&E[i][0],&E[i][1]);
        add(E[i][0],E[i][1]);
        add(E[i][1],E[i][0]);
    }
    idx = 0;
    getlist(-1,1);
}
void pushup(int rt)
{
    as[rt].mn = min(as[rt*2].mn,as[rt*2+1].mn);
    as[rt].mx = max(as[rt*2].mx,as[rt*2+1].mx);
}
void pushdown(int rt)
{
    as[rt*2].tp += as[rt].tp;
    as[rt*2+1].tp += as[rt].tp;
    as[rt*2].s += as[rt].tp;
    as[rt*2+1].s += as[rt].tp;
    as[rt*2].mn += as[rt].tp;
    as[rt*2+1].mn += as[rt].tp;
    as[rt*2].mx += as[rt].tp;
    as[rt*2+1].mx += as[rt].tp;
    as[rt].tp = 0;
}
void build(int rt,int l,int r)
{
    int m = (l + r) >> 1;
    as[rt].tp = 0;
    if(l==r){
        as[rt].mn = as[rt].mx = as[rt].s = val[vis[l]];
        as[rt].c = 1;
        return ;
    }
    build(rt*2,l,m);
    build(rt*2+1,m+1,r);
    as[rt].c = as[rt*2].c + as[rt*2+1].c;
    pushup(rt);
}

void update(int rt,int l,int r,int L,int R,int val)
{
    int m = (l + r) >> 1;
    if(l==L && r==R){
        as[rt].tp += val;
        as[rt].mn += val;
        as[rt].mx += val;
        as[rt].s += val;
        return ;
    }
    if(as[rt].tp)pushdown(rt);
    if(L>m)update(rt*2+1,m+1,r,L,R,val);
    else if(R<=m)update(rt*2,l,m,L,R,val);
    else{
        update(rt*2,l,m,L,m,val);
        update(rt*2+1,m+1,r,m+1,R,val);
    }
    pushup(rt);
}
int c,mn,mx;
void query(int rt,int l,int r,int L,int R)
{
    int m = (l + r) >> 1;
    if(l>r)return;
    if(l==L && r==R){
        c = as[rt].c;
        mn = as[rt].mn;
        mx = as[rt].mx;
        return;
    }
    if(as[rt].tp)pushdown(rt);
    if(L>m)query(rt*2+1,m+1,r,L,R);
    else if(R<=m)query(rt*2,l,m,L,R);
    else{
        query(rt*2,l,m,L,m);
        int C = c,Mn = mn, Mx = mx;
        query(rt*2+1,m+1,r,m+1,R);
        c += C;
        mn = min(Mn,mn);
        mx = max(Mx,mx);
    }
    pushup(rt);
}

int L,R;
void cal(int x)//断开第x条边时,会分出三个区间:[1,L-1]  [L,R]  [R+1,n]
{
    int a = E[x][0];
    int b = E[x][1];
    if(ls[a][0]>ls[b][0]){
        L = ls[a][0];
        R = ls[a][1];
    }else{
        L = ls[b][0];
        R = ls[b][1];
    }
}

void processing()
{
    int i,a,b,Mx,Mn;
    char op[10];
    build(1,1,n);
    while(m--){
        scanf("%s",op);
        if(op[0]=='Q'){
            scanf("%d",&i);
            cal(i);
            query(1,1,n,L,R);
            Mx = mx;
            query(1,1,n,1,L-1);
            Mn = mx;
            if(R+1<=n){
                query(1,1,n,R+1,n);
                Mn = max(mx,Mn);
            }
            printf("%d %d\n",min(Mx,Mn),max(Mx,Mn));
        }else{
            scanf("%d %d %d",&i,&a,&b);
            cal(i);
            query(1,1,n,L,R);
            if(c*2==n)continue;
            else{
                if(c*2>n){
                    update(1,1,n,L,R,max(a,b));
                    update(1,1,n,1,L-1,min(a,b));
                    if(R+1<=n)update(1,1,n,R+1,n,min(a,b));
                }else{
                    update(1,1,n,L,R,min(a,b));
                    update(1,1,n,1,L-1,max(a,b));
                    if(R+1<=n)update(1,1,n,R+1,n,max(a,b));
                }
            }
        }
    }
}
int main()
{
    int T;
    for(scanf("%d",&T);T--;){
        readin();
        processing();
    }
    return 0;
}

posted on 2012-08-15 10:57  aigoruan  阅读(179)  评论(0)    收藏  举报

导航