AmazingCounters.com

[BZOJ]1103: [POI2007]大都市meg

题目大意:一棵n个点的树,边权均为1,两种操作,一种把一条边边权改为0,另一种查询一个点到根的路径长度。(n<=250,000)

思路:预处理出一开始各个点的答案,每次修改操作把子树内的所有答案减1,求出dfs序后用线段树维护即可,复杂度O(nlogn)。

#include<cstdio>
#include<algorithm>
using namespace std;
inline int read()
{
    int x;char c;
    while((c=getchar())<'0'||c>'9');
    for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
    return x;
}
#define MN 250000
#define N 262144
struct edge{int nx,t;}e[MN*2+5];
int h[MN+5],en,l[MN+5],r[MN+5],cnt,d[MN+5],t[N*2+5];
inline void ins(int x,int y)
{
    e[++en]=(edge){h[x],y};h[x]=en;
    e[++en]=(edge){h[y],x};h[y]=en;
}
void dfs(int x,int fa)
{
    l[x]=++cnt;
    for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)d[e[i].t]=d[x]+1,dfs(e[i].t,x);
    r[x]=cnt;
}
void dec(int l,int r)
{
    for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
    {
        if(~l&1)--t[l+1];
        if( r&1)--t[r-1];
    }
}
int query(int x){int r=d[x];for(x=l[x]+N;x;x>>=1)r+=t[x];return r;}
int main()
{
    int n=read(),i,x;char s[5];
    for(i=1;i<n;++i)ins(read(),read());
    dfs(1,0);
    for(i=read()+n-1;i--;)
    {
        scanf("%s",s);
        if(s[0]=='W')printf("%d\n",query(read()));
        else x=max(read(),read()),dec(l[x],r[x]);
    }
}

 

posted on 2017-03-14 18:43  ditoly  阅读(145)  评论(0编辑  收藏  举报