Query on a graph HDU - 5957

本文详细解析了HDU 5957题目的解题思路,利用生成树、BFS序、DFS序及线段树进行区间更新和查询,通过复杂的分类讨论和区间操作实现高效解题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://acm.hdu.edu.cn/showproblem.php?pid=5957

好想但是难写

先求个生成树 并把多余边记下来 跑个bfs序并用线段树维护

bfs序和dfs序略有不同 对一个节点 遍历一遍其所有子节点并取最小最大值会得到其一级子节点在bfs序中的区间 再跑一遍就会得到二级子节点在bfs序中的区间 依此类推

然后就是恶心的分类讨论 写了一屏都没写完。。索性把所有要操作的区间都存下来 排个序去个重就好了

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int maxn=1e5+10;
const int N=0x3f3f3f3f;

struct node{
    int l,r;
};

vector <int> edge[maxn];
queue <int> que;
node pre[100];
ll sum[4*maxn],laz[4*maxn];
int f[maxn],fa[maxn],mp[maxn],lef1[maxn],rgt1[maxn],lef2[maxn],rgt2[maxn];
int n,q,uu,vv,num;

int getf(int p){
    if(f[p]==p) return p;
    else return f[p]=getf(f[p]);
}

bool unite(int u,int v){
    int fu,fv;
    fu=getf(u),fv=getf(v);
    if(fu!=fv){
        f[fv]=fu;
        return 1;
    }
    else return 0;
}

void bfs(){
    int i,u,v,cnt;
    while(!que.empty()) que.pop();
    que.push(1),fa[1]=0;
    cnt=0;
    while(!que.empty())
    {
        u=que.front();
        que.pop();
        mp[u]=++cnt;
        for(i=0;i<edge[u].size();i++){
            v=edge[u][i];
            if(v!=fa[u]) que.push(v),fa[v]=u;
        }
    }
    memset(lef1,0x3f,sizeof(lef1));
    memset(rgt1,0,sizeof(rgt1));
    for(u=1;u<=n;u++){
        for(i=0;i<edge[u].size();i++){
            v=edge[u][i];
            if(v!=fa[u]) lef1[u]=min(lef1[u],mp[v]),rgt1[u]=max(rgt1[u],mp[v]);
        }
    }
    memset(lef2,0x3f,sizeof(lef2));
    memset(rgt2,0,sizeof(rgt2));
    for(u=1;u<=n;u++){
        for(i=0;i<edge[u].size();i++){
            v=edge[u][i];
            if(v!=fa[u]) lef2[u]=min(lef2[u],lef1[v]),rgt2[u]=max(rgt2[u],rgt1[v]);
        }
    }
}

void init(){
    int i;
    for(i=1;i<=4*n;i++) sum[i]=0,laz[i]=0;
}

void pushup(int cur){
    sum[cur]=sum[2*cur]+sum[2*cur+1];
}

void pushdown(int l,int r,int cur){
    ll len;
    int m;
    if(laz[cur]!=0){
        m=(l+r)/2;
        len=m-l+1;
        sum[2*cur]+=len*laz[cur],laz[2*cur]+=laz[cur];
        len=r-m;
        sum[2*cur+1]+=len*laz[cur],laz[2*cur+1]+=laz[cur];
        laz[cur]=0;
    }
}

void update(int pl,int pr,ll val,int l,int r,int cur){
    ll len;
    int m;
    if(pl<=l&&r<=pr){
        len=r-l+1;
        sum[cur]+=len*val,laz[cur]+=val;
        return;
    }
    pushdown(l,r,cur);
    m=(l+r)/2;
    if(pl<=m) update(pl,pr,val,l,m,2*cur);
    if(pr>m) update(pl,pr,val,m+1,r,2*cur+1);
    pushup(cur);
}

ll query(int pl,int pr,int l,int r,int cur){
    ll res;
    int m;
    if(pl<=l&&r<=pr) return sum[cur];
    pushdown(l,r,cur);
    res=0,m=(l+r)/2;
    if(pl<=m) res+=query(pl,pr,l,m,2*cur);
    if(pr>m) res+=query(pl,pr,m+1,r,2*cur+1);
    return res;
}

bool cmp(node n1,node n2){
    return n1.l<n2.l;
}

void solve(){
    int i,j;
    for(i=1,j=0;i<=num;i++) if(1<=pre[i].l&&pre[i].l<=pre[i].r&&pre[i].r<=n) pre[++j]=pre[i];
    num=j;
    sort(pre+1,pre+num+1,cmp);
    for(i=1,j=0;i<=num;i++){
        if(j==0||pre[i].l>pre[j].r) pre[++j]=pre[i];
        else pre[j].r=max(pre[j].r,pre[i].r);
    }
    num=j;
}

int main(){
    ll d,res;
    int t,i,u,v,k;
    char op[10];
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(i=1;i<=n;i++) edge[i].clear();
        for(i=1;i<=n;i++) f[i]=i;
        for(i=1;i<=n;i++){
            scanf("%d%d",&u,&v);
            if(unite(u,v)) edge[u].pb(v),edge[v].pb(u);
            else uu=u,vv=v;
        }
        //printf("***%d %d***\n",uu,vv);
        bfs();
        init();
        scanf("%d",&q);
        while(q--){
            scanf("%s",op);
            if(op[0]=='M'){
                scanf("%d%d%lld",&u,&k,&d);
                if(k==0) update(mp[u],mp[u],d,1,n,1);
                else if(k==1){
                    num=0;
                    pre[++num].l=mp[fa[u]],pre[num].r=mp[fa[u]];
                    pre[++num].l=mp[u],pre[num].r=mp[u];
                    pre[++num].l=lef1[u],pre[num].r=rgt1[u];
                    if(u==uu) pre[++num].l=mp[vv],pre[num].r=mp[vv];
                    else if(u==vv) pre[++num].l=mp[uu],pre[num].r=mp[uu];
                    solve();
                    //for(i=1;i<=num;i++) printf("*%d %d*\n",pre[i].l,pre[i].r);
                    for(i=1;i<=num;i++) update(pre[i].l,pre[i].r,d,1,n,1);
                }
                else{
                    num=0;
                    pre[++num].l=mp[fa[fa[u]]],pre[num].r=mp[fa[fa[u]]];
                    pre[++num].l=mp[fa[u]],pre[num].r=mp[fa[u]];
                    pre[++num].l=lef1[fa[u]],pre[num].r=rgt1[fa[u]];
                    pre[++num].l=mp[u],pre[num].r=mp[u];
                    pre[++num].l=lef1[u],pre[num].r=rgt1[u];
                    pre[++num].l=lef2[u],pre[num].r=rgt2[u];
                    if(fa[u]==uu||fa[u]==vv||(lef1[u]<=mp[uu]&&mp[uu]<=rgt1[u])||(lef1[u]<=mp[vv]&&mp[vv]<=rgt1[u])){
                        if(fa[u]==vv||(lef1[u]<=mp[vv]&&mp[vv]<=rgt1[u])) swap(uu,vv);
                        pre[++num].l=mp[vv],pre[num].r=mp[vv];
                    }
                    else if(u==uu||u==vv){
                        if(u==vv) swap(uu,vv);
                        pre[++num].l=mp[fa[vv]],pre[num].r=mp[fa[vv]];
                        pre[++num].l=mp[vv],pre[num].r=mp[vv];
                        pre[++num].l=lef1[vv],pre[num].r=rgt1[vv];
                    }
                    solve();
                    //for(i=1;i<=num;i++) printf("*%d %d*\n",pre[i].l,pre[i].r);
                    for(i=1;i<=num;i++) update(pre[i].l,pre[i].r,d,1,n,1);
                }
            }
            else{
                scanf("%d%d",&u,&k);
                if(k==0) res=query(mp[u],mp[u],1,n,1);
                else if(k==1){
                    num=0;
                    pre[++num].l=mp[fa[u]],pre[num].r=mp[fa[u]];
                    pre[++num].l=mp[u],pre[num].r=mp[u];
                    pre[++num].l=lef1[u],pre[num].r=rgt1[u];
                    if(u==uu) pre[++num].l=mp[vv],pre[num].r=mp[vv];
                    else if(u==vv) pre[++num].l=mp[uu],pre[num].r=mp[uu];
                    solve();
                    res=0;
                    //for(i=1;i<=num;i++) printf("*%d %d*\n",pre[i].l,pre[i].r);
                    for(i=1;i<=num;i++) res+=query(pre[i].l,pre[i].r,1,n,1);
                }
                else{
                    num=0;
                    pre[++num].l=mp[fa[fa[u]]],pre[num].r=mp[fa[fa[u]]];
                    pre[++num].l=mp[fa[u]],pre[num].r=mp[fa[u]];
                    pre[++num].l=lef1[fa[u]],pre[num].r=rgt1[fa[u]];
                    pre[++num].l=mp[u],pre[num].r=mp[u];
                    pre[++num].l=lef1[u],pre[num].r=rgt1[u];
                    pre[++num].l=lef2[u],pre[num].r=rgt2[u];
                    if(fa[u]==uu||fa[u]==vv||(lef1[u]<=mp[uu]&&mp[uu]<=rgt1[u])||(lef1[u]<=mp[vv]&&mp[vv]<=rgt1[u])){
                        if(fa[u]==vv||(lef1[u]<=mp[vv]&&mp[vv]<=rgt1[u])) swap(uu,vv);
                        pre[++num].l=mp[vv],pre[num].r=mp[vv];
                    }
                    else if(u==uu||u==vv){
                        if(u==vv) swap(uu,vv);
                        pre[++num].l=mp[fa[vv]],pre[num].r=mp[fa[vv]];
                        pre[++num].l=mp[vv],pre[num].r=mp[vv];
                        pre[++num].l=lef1[vv],pre[num].r=rgt1[vv];
                    }
                    solve();
                    res=0;
                    //for(i=1;i<=num;i++) printf("*%d %d*\n",pre[i].l,pre[i].r);
                    for(i=1;i<=num;i++) res+=query(pre[i].l,pre[i].r,1,n,1);
                }
                printf("%lld\n",res);
            }
        }
    }
    return 0;
}

/*
1
18
1 2
1 3
2 4
2 5
3 6
3 7
4 8
4 9
7 10
7 11
7 12
8 13
8 14
10 15
10 16
12 17
12 18
6 15
10
M 6 1 5
M 6 2 5
M 6 0 5
M 15 1 2
Q 10 2
*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值