zoukankan      html  css  js  c++  java
  • 【NOI2015】软件包管理器

    NOI难得的水题,话说还是T2诶……又学到了线段树的一种新的魔性使用

    看sxysxy大神的代码才写出来的,sxysxy_orz

    原题:

    Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器。

    你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,…,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,Am−1依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
    现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。
    n=100000,q=100000

    主要就是两种树上线段树,树剖和dfs序列化,很裸,不过这里有一种线段树的魔性使用:(2017.12.5 upd:其实这就是个常规的赋值应用,我当年真是naive23333

    给线段树修改的时候,delta不是+=z,而是=z,这个表示吧一个区间里面所有的数都变成z,一般用区间里面的数为1或0来表示有没有

    然后在计算value(这里表示一个区间里面有几个)的时候应该是tree[x].delta*(tree[x].sright-tree[x].sleft+1);表示这一段区间里的东西要么有(delta=1),要么没有(delta=0),乘上长度就是有的个数

    添加的时候先查一下这个点上面有几个,然后buff一下,用buff的长度减去之前查找的个数,就是需要再添加的个数

    然后就是两种树上线段树结合一下很开心的水过了,因为树链的一端只能是根节点,所以在爬链的时候比原版本还要简单

    不过写的时候犯了一个非常傻逼的错误,调了几十分钟

    x=father[top[x]]写成x=father[x],整整多了几条链的复杂度qaqqqqqqqqqqqqqqqq

    还以为是卡常问题,找了好长时间……

    说一下几点需要注意的地方:

    0是有意义的,所以如果没有重儿子要设成-1

    同样因为标号从0开始,所以总共有7个点,但是标号只到6,dfs序的计数器初始化要设成-1(从0开始)

    代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath>
      6 using namespace std;
      7 int read(){int z=0,mark=1;  char ch=getchar();
      8     while(ch<'0'||ch>'9'){if(ch=='-')mark=-1;  ch=getchar();}
      9     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
     10     return z*mark;
     11 }
     12 struct ddd{int next,y;}e[110000];int LINK[110000],ltop=0;
     13 inline void insert(int x,int y){e[++ltop].next=LINK[x];LINK[x]=ltop;e[ltop].y=y;}
     14 int n,m;
     15 int size[110000],deep[110000],father[110000],big_child[110000],top[110000],n_value[110000];
     16 int dfs_xv[110000],fan_xv[110000],er_xv[110000],xv_cnt=-1;//注意因为从0开始,所以总共有7个点,但是编号只到6
     17 void dfs1(int x,int _father,int _deep){
     18     father[x]=_father,deep[x]=_deep,size[x]=1;
     19     int max_size=0,max_child=-1;//注意0有意义
     20     for(int i=LINK[x];i;i=e[i].next)if(e[i].y!=father[x]){
     21         dfs1(e[i].y,x,_deep+1);
     22         size[x]+=size[e[i].y];
     23         if(size[e[i].y]>max_size)  max_size=size[e[i].y],max_child=e[i].y;
     24     }
     25     big_child[x]=max_child;
     26 }
     27 void dfs2(int x,int _top){
     28     top[x]=_top;  dfs_xv[++xv_cnt]=x;  fan_xv[x]=xv_cnt;
     29     if(big_child[x]!=-1)  dfs2(big_child[x],_top);//注意-1
     30     for(int i=LINK[x];i;i=e[i].next)if(e[i].y!=father[x] && e[i].y!=big_child[x])
     31         dfs2(e[i].y,e[i].y);
     32     er_xv[x]=xv_cnt;
     33 }
     34 struct dcd{int sleft,sright,mid,svalue,delta;}tree[5100000];
     35 void stev(int x){  tree[x].svalue=tree[x].delta*(tree[x].sright-tree[x].sleft+1);}//sxysxy_orz
     36 void get_SegmentTree(int x,int _left,int _right){
     37     tree[x].sleft=_left,tree[x].sright=_right,tree[x].mid=(_left+_right)>>1;
     38     tree[x].svalue=tree[x].delta=0;
     39     if(_left!=_right)  get_SegmentTree(x<<1,_left,tree[x].mid),get_SegmentTree(x<<1|1,tree[x].mid+1,_right);
     40 }
     41 int search(int x,int _left,int _right){
     42     if(tree[x].sleft==_left && tree[x].sright==_right)  return tree[x].svalue;
     43     else{
     44         if(tree[x].delta!=-1){
     45             tree[x<<1].delta=tree[x<<1|1].delta=tree[x].delta;  tree[x].delta=-1;//注意这里并不是加上,而是设置为,注意-1 (sxysxy_orz
     46             stev(x<<1),stev(x<<1|1);
     47             tree[x].delta=-1;
     48         }
     49         if(_left<=tree[x].mid && _right>tree[x].mid)  return search(x<<1,_left,tree[x].mid)+search(x<<1|1,tree[x].mid+1,_right);
     50         else if(_right<=tree[x].mid)  return search(x<<1,_left,_right);
     51         else  return search(x<<1|1,_left,_right);
     52     }
     53 }
     54 void buff(int x,int _left,int _right,int z){
     55     if(tree[x].sleft==_left && tree[x].sright==_right)  tree[x].delta=z,stev(x);
     56     else{
     57         if(tree[x].delta!=-1){
     58             tree[x<<1].delta=tree[x<<1|1].delta=tree[x].delta;  tree[x].delta=-1;
     59             stev(x<<1),stev(x<<1|1);
     60             tree[x].delta=-1;
     61         }
     62         if(_left<=tree[x].mid && _right>tree[x].mid)  buff(x<<1,_left,tree[x].mid,z),buff(x<<1|1,tree[x].mid+1,_right,z);
     63         else if(_right<=tree[x].mid)  buff(x<<1,_left,_right,z);
     64         else  buff(x<<1|1,_left,_right,z);
     65         tree[x].svalue=tree[x<<1].svalue+tree[x<<1|1].svalue;
     66     }
     67 }
     68 int install(int x){
     69     int ans=0;
     70     while(x!=-1){
     71         ans+=fan_xv[x]-fan_xv[top[x]]+1-search(1,fan_xv[top[x]],fan_xv[x]);
     72         buff(1,fan_xv[top[x]],fan_xv[x],1);
     73         //x=father[x]  我是傻逼qaqqqqqqqqqqqqqqqqqqqq
     74         x=father[top[x]];
     75     }
     76     return ans;
     77 }
     78 int uninstall(int x){
     79     int ans=search(1,fan_xv[x],er_xv[x]);
     80     buff(1,fan_xv[x],er_xv[x],0);
     81     return ans;
     82 }
     83 int main(){
     84     /*freopen("ddd.in","r",stdin);
     85     freopen("ddd.out","w",stdout);*/
     86     freopen("manager.in","r",stdin);
     87     freopen("manager.out","w",stdout);
     88     cin>>n;
     89     for(int i=1;i<n;i++)  insert(read(),i),n_value[i]=0;
     90     dfs1(0,-1,1),dfs2(0,0),get_SegmentTree(1,0,n-1);
     91     cin>>m;
     92     char ch;  int _id;
     93     while(m --> 0){//趋向于
     94         ch=getchar(); 
     95            while(ch!='i' && ch!='u')  ch=getchar();
     96         if(ch=='i'){
     97             for(int i=1;i<=6;i++)  ch=getchar();
     98             _id=read();
     99             printf("%d
    ",install(_id));
    100         }
    101         else{
    102             for(int i=1;i<=8;i++)  ch=getchar();
    103             _id=read();
    104             printf("%d
    ",uninstall(_id));
    105         }
    106     }
    107     return 0;
    108 }
    View Code
  • 相关阅读:
    Android 编程下 Eclipse 恢复被删除的文件
    Android 编程下背景图片适配工具类
    Android 编程下 Managing Your App's Memory
    Android 编程下代码之(QQ消息列表滑动删除)
    Android 编程下 Canvas and Drawables
    Android 编程下 AlarmManager
    Android 编程下去除 ListView 上下边界蓝色或黄色阴影
    Java 编程下字符串的 16 位、32位 MD5 加密
    C#枚举类型和int类型相互转换
    MVC和普通三层架构的区别
  • 原文地址:https://www.cnblogs.com/JSL2018/p/5907108.html
Copyright © 2011-2022 走看看