PowerOJ1179-树链剖分

题目链接:  PowerOj1179


 1179: 我要10个G

Time Limit:  8500 MS Memory Limit:  2097152 KB
Total Submit:  7 Accepted:  5 Page View:  21
Submit  Status  Discuss

    大黄对于以太网的速度要求不是一般的高,要求达到10Gbps的速度。于是上决╇ф把实验室内的网络设备全部更换成了万兆的。由于资金紧缺,上决╇ф不得不从深水宝购买这些万兆设备。后果可想而知,这些设备的的稳定性不堪入目,经常罢工。然而大黄和梁晨这小两口经常换位置。大黄想知道,每次换位置后,她和梁晨之间的网络是否通畅。


输入第一行两个正整数 n,qn,q 1n,q1051≤n,q≤105),分别代表实验室内网络设备的个数和日志条数。 接下来 n1n−1行,每行有两个正整数 u,vu,v 1u,vn1≤u,v≤n)。表示编号为 uu的设备和编号为 vv的设备之间通过一条高贵的七类屏蔽线连接。 接下来 qq行,第一个数 optopt 1opt31≤opt≤3)代表日志类别。 当 opt=1opt=1时,后面将会有两个正整数 u,vu,v 1u,vn1≤u,v≤n)。表示现在大黄的电脑连接在编号为 uu设备上,梁晨的电脑连接连接在编号为 vv的设备上。询问大黄和梁晨之间的网络是否通畅。 当 opt=2opt=2时,后面将会有一个正整数 uu 1un1≤u≤n)。表示编号为 uu的设备被上决╇ф修好了。 当 opt=3opt=3时,后面将会有一个正整数 uu 1un1≤u≤n)。表示编号为 uu的设备损坏了。 输入保证任意两台设备都是直接或间接地通过网线连通的。初始的时候,所有的网络设备都是正常工作的。并且保证不会维修一个好的设备,也不会出现已损坏的设备再次损坏的情况。
对于每一次询问日志,如果大黄和梁晨之间的网络通畅,没有损坏的设备,输出“YES”,否则“NO”
7 82 13 24 35 46 17 11 7 63 21 3 73 41 6 23 11 5 21 3 5
YESNONONONO


题目大意:


给你一颗n个节点的树和q次查询,查询为

1 u v  问u->v是否联通

2 u  将u节点修复好

3 u  u节点损坏

初始都是好的,,保证输入合法不存在修复好的节点,损坏坏的节点


题目思路:


对于树上节点区间的查询和节点的修改我们很好想到的是树链剖分,对于初始时所有节点的值为1,如果查询u->v

是否联通则u->v的距离为他们之间经过点的个数,如果不等则不联通,对于树链求点数可以先求出lca来

再根据深度算出来


AC代码:


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
 
using namespace std;
 
const int maxn = 2e5+100;
 
/** 邻接表部分  */
 
struct st
{
    int v,nex;
}edge[maxn<<1];
 
int head[maxn],e;
 
void add(int u,int v)
{
    edge[e].v = v,edge[e].nex = head[u],head[u]=e++;
}
 
/**  树链剖分部分   */
 
int fa[maxn],dep[maxn],siz[maxn],top[maxn],son[maxn],pos[maxn],rak[maxn],val[maxn];;
int tim;
 
void dfs(int u,int pr,int d)
{
    siz[u] = 1,dep[u]=d,fa[u] = pr;
    for(int i = head[u];~i;i=edge[i].nex)
    {
        int v = edge[i].v;
        if(v==pr)continue;
        dfs(v,u,d+1);
        siz[u]+=siz[v];
        if(son[u]==-1||siz[son[u]]<siz[v])
            son[u]=v;
    }
}
 
void create(int u,int tp)
{
    top[u] = tp;
    pos[u] = ++tim;
    rak[pos[u]] = u;
    if(son[u]==-1)return ;
    create(son[u],tp);
    for(int i=head[u];~i;i=edge[i].nex)
    {
        int v = edge[i].v;
        if(v != fa[u]&&v != son[u])create(v,v);
    }
}
 
/**  线段树部分  */
 
struct nod
{
    int l,r;
    int sum,c;
}node[maxn<<3];
 
void pushdown(int rt,int m)
{
    node[rt<<1].c+=node[rt].c;
    node[rt<<1|1].c+=node[rt].c;
 
    node[rt<<1].sum+=node[rt].c*(m-m/2);
    node[rt<<1|1].sum+=node[rt].c*(m/2);
 
    node[rt].c = 0;
}
 
void pushup(int rt)
{
    node[rt].sum = node[rt<<1].sum+node[rt<<1|1].sum;
}
 
void BuildTree(int l,int r,int rt)
{
    node[rt].l = l,node[rt].r = r,node[rt].c =0;
    if(l==r)
    {
        node[rt].sum = val[rak[l]];
        return ;
    }
    int mid = (l+r)>>1;
    BuildTree(l,mid,rt<<1);
    BuildTree(mid+1,r,rt<<1|1);
    pushup(rt);
}
 
void update(int l,int r,int rt,int w)
{
    if(l<=node[rt].l&&r>=node[rt].r)
    {
        node[rt].sum+=(node[rt].r-node[rt].l+1)*w;
        node[rt].c+=w;
        return ;
    }
    if(node[rt].c)pushdown(rt,node[rt].r-node[rt].l+1);
    int mid = (node[rt].l+node[rt].r)>>1;
    if(l<=mid)update(l,r,rt<<1,w);
    if(r>mid)update(l,r,rt<<1|1,w);
    pushup(rt);
}
 
int quary(int L,int R,int l,int r,int rt)
{
    if(r<L||l>R)return 0;
    if(L<=l&&R>=r)return node[rt].sum;
    int mid = (l+r)>>1;
 
    if(node[rt].c)pushdown(rt,r-l+1);
    return quary(L,R,l,mid,rt<<1)+quary(L,R,mid+1,r,rt<<1|1);
 
}
 
/**  运行部分   */
int n,m,p;
int len;
void change(int x,int y,int w)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(pos[top[x]],pos[x],1,w);
        x = fa[top[x]];
 
    }
    if(dep[x]>dep[y])swap(x,y);
    update(pos[x],pos[y],1,w);
}
 
int SUM(int x,int y)
{
    len = 0;  			//记录点数
    int sum = 0;		//记录距离
    while(top[x]!=top[y])
    {
 
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        sum+=quary(pos[top[x]],pos[x],1,n,1);
        len+=abs(dep[x]-dep[fa[top[x]]]);
        x = fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    len+=dep[y]-dep[x]+1;
    sum+=quary(pos[x],pos[y],1,n,1);
    return sum;
 
}
 
void init()
{
    tim = e = 0;
    memset(head,-1,sizeof(head));
    memset(son,-1,sizeof(son));
}
 
void sove()
{
    for(int i=1;i<=n;i++)val[i] = 1;
    for(int i=1;i<n;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs(1,1,1);
    create(1,1);
    BuildTree(1,n,1);
    while(p--)
    {
        int s;
        int x,y,w;
        scanf("%d",&s);
        if(s==1)
        {
            scanf("%d%d",&x,&y);
            int xx = SUM(x,y);
            if(xx==len)printf("YES\n");
            else printf("NO\n");
        }
        else if(s==2)
        {
            scanf("%d",&x);
            change(x,x,1);
        }
        else
        {
            scanf("%d",&x);
            change(x,x,-1);
        }
    }
}
 
int main()
{
    scanf("%d%d",&n,&p);
    init();
    sove();
    return 0;
}








#include <cstdio> #include <iostream> #include <vector> #define N 30003 #define INF 2147483647 using namespace std; int n,f[N][20],dep[N],siz[N],son[N],top[N],tot,pos[N],w[N]; int Max[N*4],Sum[N*4]; vector <int> to[N]; void dfs1(int x){ siz[x]=1; int sz=to[x].size(); for(int i=0;i<sz;++i){ int y=to[x][i]; if(y==f[x][0])continue; f[y][0]=x; dep[y]=dep[x]+1; dfs1(y); siz[x]+=siz[y]; if(siz[y]>siz[son[x]])son[x]=y; } } void dfs2(int x,int root){ top[x]=root; pos[x]=++tot; if(son[x])dfs2(son[x],root); int sz=to[x].size(); for(int i=0;i<sz;++i){ int y=to[x][i]; if(y==f[x][0] || y==son[x])continue; dfs2(y,y); } } void update(int k,int l,int r,int P,int V){ if(l==r){ Max[k]=Sum[k]=V; return; } int mid=(l+r)>>1; if(P<=mid)update(k*2,l,mid,P,V); else update(k*2+1,mid+1,r,P,V); Max[k]=max(Max[k*2],Max[k*2+1]); Sum[k]=Sum[k*2]+Sum[k*2+1]; } void up(int &x,int goal){ for(int i=15;i>=0;--i) if(dep[f[x][i]]>=goal)x=f[x][i]; } int lca(int x,int y){ if(dep[x]>dep[y])up(x,dep[y]); if(dep[x]<dep[y])up(y,dep[x]); if(x==y)return x; for(int i=15;i>=0;--i) if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } int getm(int k,int l,int r,int L,int R){ if(L<=l && r<=R)return Max[k]; int res=-INF,mid=(l+r)>>1; if(L<=mid)res=max(res,getm(k*2,l,mid,L,R)); if(R>mid)res=max(res,getm(k*2+1,mid+1,r,L,R)); return res; } int gets(int k,int l,int r,int L,int R){ if(L<=l && r<=R)return Sum[k]; int res=0,mid=(l+r)>>1; if(L<=mid)res+=gets(k*2,l,mid,L,R); if(R>mid)res+=gets(k*2+1,mid+1,r,L,R); return res; } int main(){ scanf("%d",&n); for(int i=1,a,b;i<n;++i){ scanf("%d%d",&a,&b); to[a].push_back(b); to[b].push_back(a); } dep[1]=1; dfs1(1); dfs2(1,1); for(int i=1;i<=15;++i) for(int j=1;j<=n;++j)f[j][i]=f[f[j][i-1]][i-1]; for(int i=1;i<=n;++i){ scanf("%d",&w[i]); update(1,1,n,pos[i],w[i]); } int q; scanf("%d",&q); while(q--){ char s[10]; int u,v,t; scanf("%s",s); if(s[1]=='H'){ scanf("%d%d",&u,&t); w[u]=t; update(1,1,n,pos[u],t); } if(s[1]=='M'){ scanf("%d%d",&u,&v); int ans=-INF,t=lca(u,v); for(int i=u;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans=max(ans,getm(1,1,n,pos[top[i]],pos[i])); else{ ans=max(ans,getm(1,1,n,pos[t],pos[i])); break; } for(int i=v;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans=max(ans,getm(1,1,n,pos[top[i]],pos[i])); else{ ans=max(ans,getm(1,1,n,pos[t],pos[i])); break; } printf("%d\n",ans); } if(s[1]=='S'){ scanf("%d%d",&u,&v); int ans=0,t=lca(u,v); for(int i=u;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans+=gets(1,1,n,pos[top[i]],pos[i]); else{ ans+=gets(1,1,n,pos[t],pos[i]); break; } for(int i=v;i;i=f[top[i]][0]) if(dep[t]<dep[top[i]]) ans+=gets(1,1,n,pos[top[i]],pos[i]); else{ ans+=gets(1,1,n,pos[t],pos[i]); break; } printf("%d\n",ans-w[t]); } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值