P3285 松鼠的新家 (树链剖分)

题目描述

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。

松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致**重复走很多房间,懒惰的**不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

**是个馋家伙,立马就答应了。现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。

因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。

输入输出格式

输入格式:

第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

输出格式: 

一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让**有糖果吃。

输入输出样例

输入样例#1: 
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出样例#1: 
1
2
1
2
1

说明

2<= n <=300000

因为这个题,只要最后面查询,所以可以用树状数组的区间修改来做,所以,上代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define ll(x) (x*2)
#define rr(x) (x*2+1)
#define lol long long 
using namespace std;
const int maxn=300008;

lol read()
{
    char ch=getchar();lol f=1,w=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){w=w*10+ch-'0';ch=getchar();}
    return f*w;
}

struct sj{
    lol to;
    lol next;
}a[maxn*2];
lol head[maxn],size;
lol vis[maxn],js[maxn],n;
lol top[maxn],son[maxn],num[maxn];
lol id[maxn],dep[maxn],fa[maxn];
lol c[maxn],nat[maxn];

void add(lol x,lol y)
{
    a[++size].to=y;
    a[size].next=head[x];
    head[x]=size;
}
    
void dfs(lol rt,lol pre,lol deep)
{
    dep[rt]=deep;
    num[rt]=1;
    fa[rt]=pre;
    for(int i=head[rt];i;i=a[i].next)
    {
        lol tt=a[i].to;
        if(tt!=fa[rt])
        {
            dfs(tt,rt,deep+1);
            num[rt]+=num[tt];
            if(num[tt]>num[son[rt]])
            son[rt]=tt;
        }
    }
}

int dfn;    
void dfs_find(lol rt,lol zu)
{
    dfn++;
    top[rt]=zu; 
    id[rt]=dfn;
    if(son[rt]!=-1) 
    dfs_find(son[rt],zu);
    for(int i=head[rt];i;i=a[i].next)
    {
        lol tt=a[i].to;
        if(tt!=son[rt]&&tt!=fa[rt])
        {
            dfs_find(tt,tt);
        }
    }
    return;
}    

int lowbit(int x)
{
    return x&(-x);
}

void insert(int x,int z)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {if(i==0)break;c[i]+=z;}
}

int check(int x)
{
    int sum=0;
    for(int i=x;i>=1;i-=lowbit(i))
    {
      sum+=c[i];
    }
    return sum;
}    

void change(int s,int t)                                            //change 还有一点*问题 没有剪掉起点
{    
    while(top[s]!=top[t])
    {
        if(dep[top[s]]<dep[top[t]])
        swap(s,t);
        insert(id[top[s]],1);
        insert(id[s]+1,-1);
        s=fa[top[s]];
    }
    if(id[s]>id[t])
    swap(s,t);
    insert(id[s],1);
    insert(id[t]+1,-1);
    return;
}
    
int main()
{
    memset(son,-1,sizeof(son));
    memset(top,-1,sizeof(top));
    n=read();
    for(int i=1;i<=n;i++)
    vis[i]=read();
    for(int i=1;i<n;i++)
    {
        lol x,y;
        x=read(); y=read();
        add(x,y); add(y,x);
    }
    dfs(1,0,1); dfs_find(1,1); 
    js[vis[1]]+=1; js[vis[n]]-=1;
    for(int i=1;i<n;i++)
    {
        change(vis[i],vis[i+1]);
        js[vis[i]]-=1;
    }
    for(int i=1;i<=n;i++)
    {
        lol ss;
        ss=check(id[i]);
        ss+=js[i];
        cout<<ss<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Kv-Stalin/p/8195630.html