Evanyou Blog 彩带

NOI2015 D1T2 软件包管理器

  题目传送门;

  这个貌似是我这个蒟蒻做的第一道NOI系列的题了吧。。。这题的算法是树链剖分,其实基本上就是很常见的树剖+线段树,题目既然是要求每次安装或卸载改变的软件包的数目,那么就在每次操作前记录下线段树中根节点的权值,再进行修改,修改后的根节点的值与先前记录的值的差的绝对值就是改变的软件包的数目。思想并不复杂,但是这一类代码量比较大的题有很多细节要注意,这里我就不一一地说了。

  另外,这个题目中的软件包是从0开始标号的,为了方便操作,可以把所有软件包的标号都+1。

  下面是AC代码:

  (蒟蒻手写的代码效率也还行,最慢的点236ms)  

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=200010;
int n,m,anum,depth[N],head[N];
int xu[N],id,num[N],fa[N];
int size[N],top[N],hson[N];
int segtree[N<<2],sign[N<<2];
struct Node{
  int to,next;
}edge[N<<1];
inline int read()
{
  char ch=getchar();int num=0;bool flag=false;
  while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
  while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
  return flag?-num:num;
}
inline int Abs(int x)
{return x>0?x:-x;}
inline void add(int x,int y)
{
  edge[++anum].to=y;
  edge[anum].next=head[x];
  head[x]=anum;
}
inline void dfs1(int u)
{
  size[u]=1;
  for(int i=head[u];i!=-1;i=edge[i].next){
    int v=edge[i].to;
    if(v==fa[u])continue;
    depth[v]=depth[u]+1;fa[v]=u;
    dfs1(v);size[u]+=size[v];
    if(!hson[u]||size[v]>size[hson[u]])
      hson[u]=v;
  }
}
inline void dfs2(int u,int nowtop)
{
  xu[++id]=u;num[u]=id;top[u]=nowtop;
  if(!hson[u])return;dfs2(hson[u],nowtop);
  for(int i=head[u];i!=-1;i=edge[i].next){
    int v=edge[i].to;
    if(v==fa[u]||v==hson[u])continue;
    dfs2(v,v);
  }
}
inline void pushup(int root)
{segtree[root]=segtree[root<<1]+segtree[root<<1|1];}
inline void pushdown(int root,int l,int r)
{
  if(sign[root]!=-1){
    int mid=(l+r)>>1;
    segtree[root<<1]=(mid-l+1)*sign[root];
    segtree[root<<1|1]=(r-mid)*sign[root];
    sign[root<<1]=sign[root];
    sign[root<<1|1]=sign[root];
    sign[root]=-1;
  }
}
inline void build(int l,int r,int root)
{
  segtree[root]=0;
  if(l==r)return;
  int mid=(l+r)>>1;
  build(l,mid,root<<1);
  build(mid+1,r,root<<1|1);
  pushup(root);
}
inline void update(int l,int r,int root,int L,int R,int C)
{
  if(r<L||l>R)return;
  if(L<=l&&r<=R){
    segtree[root]=(r-l+1)*C;
    sign[root]=C;return;}
  int mid=(l+r)>>1;
  pushdown(root,l,r);
  if(L<=mid)update(l,mid,root<<1,L,R,C);
  if(R>mid)update(mid+1,r,root<<1|1,L,R,C);
  pushup(root);
}
inline void change(int x,int y,int val)
{
  int fax=top[x],fay=top[y];
  while(fax!=fay){
    if(depth[fax]<depth[fay])
      {swap(fax,fay);swap(x,y);}
    update(1,n,1,num[fax],num[x],val);
    x=fa[fax];fax=top[x];
  }
  if(depth[x]>depth[y])swap(x,y);
  update(1,n,1,num[x],num[y],val);
}
void ready()
{
  memset(head,-1,sizeof(head));
  memset(sign,-1,sizeof(sign));
  n=read();
  for(int i=1;i<n;i++){
    int x=read();
    add(i+1,x+1);
    add(x+1,i+1);
  }
  fa[1]=1;depth[1]=1;
  dfs1(1);dfs2(1,1);
  build(1,n,1);
}
void work()
{
  m=read();char ka[10];
  for(int i=1;i<=m;i++){
    scanf("%s",ka);
    int t1=segtree[1];
    int x=read();x++;
    if(ka[0]=='i'){
      change(1,x,1);
      int t2=segtree[1];
      printf("%d\n",Abs(t2-t1));
    }
    if(ka[0]=='u'){
      update(1,n,1,num[x],num[x]+size[x]-1,0);
      int t2=segtree[1];
      printf("%d\n",Abs(t1-t2));
    }
  }
}
int main()
{
  ready();
  work();
  return 0;
}

 

posted @ 2018-01-11 21:31  HolseLee  阅读(289)  评论(0编辑  收藏  举报