NOI2015 软件包管理器 树剖+线段树

来源:互联网 发布:mysql自定义排序规则 编辑:程序博客网 时间:2024/06/07 15:38

题目背景是一个安装与卸载软件的系统,软件之间关系是一棵树,以0为根节点。当你安装一个软件时需要先安装它的所有祖先,卸载时则要先卸载整个子树。对每一次操作询问改变状态的软件数目。

思路:dfs序做树剖,用线段树维护数据。

#include<iostream>#include<vector>#include<stdio.h>#define ls (id*2)#define rs (id*2+1)using namespace std;vector<int> lin[100005];int in[100005],size[100005],fa[100005],top[100005],n,num,ans;struct node{    int val;    int lazy;}t[100005*4];int abs(int a){    return a>=0?a:-a;}void push_down(int id,int l,int mid,int r){    if (t[id].lazy==-1)return;    t[ls].lazy=t[id].lazy;    t[rs].lazy=t[id].lazy;    t[ls].val=(mid-l+1)*t[id].lazy;    t[rs].val=(r-mid)*t[id].lazy;    t[id].lazy=-1;}void push_up(int id){    t[id].val=t[ls].val+t[rs].val;}void build(int id,int l,int r){    if(l==r)    {        t[id].val=0;        t[id].lazy=-1;//改成-1!切记!         return;    }    int mid=(l+r)/2;    build(ls,l,mid);    build(rs,mid+1,r);    push_up(id);}void insert(int id,int l,int r,int L,int R,int V){    if(r<L||l>R) return;    if(r<=R && l>=L)    {        ans+=abs(V*(r-l+1)-t[id].val);        t[id].val=V*(r-l+1);        t[id].lazy=V;        return;    }    int mid=(l+r)/2;    push_down(id,l,mid,r);    insert(ls,l,mid,L,R,V);    insert(rs,mid+1,r,L,R,V);    push_up(id);}void dfs1(int x,int pre){    in[x]=++num;    fa[x]=pre;    for (int i=0;i<lin[x].size();i++)    {        int nex=lin[x][i];        if (nex==pre)   continue;        dfs1(nex,x);    }    size[x]=num-in[x]+1;//必须+1,否则dfs2中判断叶子节点很麻烦。}void dfs2(int x,int t){    in[x]=++num;    top[x]=t;    if (size[x]==1) return;//叶子节点直接返回,否则会死循环(不能用size[x]=0做!)    int msize=0,heavy=0;//都要赋初始值!    for (int i=0;i<lin[x].size();i++)    {        int nex=lin[x][i];        if (nex==fa[x]) continue;        if (size[nex]>msize)        {            msize=size[nex];            heavy=nex;        }    }    dfs2(heavy,t);//先走重儿子,其他随意    for (int i=0;i<lin[x].size();i++)    {        int nex=lin[x][i];        if (nex==fa[x] || nex==heavy) continue;        dfs2(nex,nex);    }}int main(){    cin>>n;    for (int i=1;i<n;i++)    {        int a;        cin>>a;//编号都+1,防止爆线段树         lin[a+1].push_back(i+1);        lin[i+1].push_back(a+1);    }    num=0;  dfs1(1,0);    num=0;  dfs2(1,1);    int q;      cin>>q;    char s[15];    while (q--)    {        int a;        scanf("%s",s);//一定不要用cin!!!!T了半个小时...        scanf("%d",&a);        a++;        if (s[0]=='i')        {            ans=0;            while (a!=0)            {                insert(1,1,n,in[top[a]],in[a],1);                a=fa[top[a]];            }             printf("%d\n",ans);        }        if (s[0]=='u')        {            ans=0;            insert(1,1,n,in[a],in[a]+size[a]-1,0);            printf("%d\n",ans);        }    }}
1 0
原创粉丝点击