• [BZOJ4399]魔法少女LJJ


    题目大意:
    一个动态图,支持以下$7$种操作:
    1.加入一个权值为$x$的点;
    2.在点$a$和点$b$之间加入一条无向边;
    3.在点$a$所属的连通块中将小于$x$的所有权值修改为$x$;
    4.在点$a$所属的连通块中将大于$x$的所有权值修改为$x$;
    5.查找点$a$所属的连通块中第$k$小的权值;
    6.比较点$a$所属连通块中所有权值之积与点$b$所属连通块中所有权值之积的大小;
    7.询问点$a$所属的连通块的大小。

    思路:
    建立一棵动态开点的权值线段树,支持以下$7$种操作:
    1.插入一个点(新建一棵树);
    2.合并两棵树(并查集);
    3.询问$[1,x-1]$的元素个数,单点修改加到$x$上,并区间修改删除$[1,x-1]$的权值;
    4.询问$[x+1,n]$的元素个数,单点修改加到$x$上,并区间修改删除$[x+1,n]$的权值;
    5.查找全树第$k$最值;
    6.对于线段树每个结点维护$log$值,因为$ln(a imes b)=ln(a)+ln(b)$,所以每次加起来比较和就行了;
    7.返回整棵树的元素个数。
    另外因为数据范围比较大需要离散化,要事先将整个文件读进来。

    玄学问题:
    1.区间修改打lazy tag似乎和暴力修改差不多,甚至会更慢;
    2.似乎很容易被卡内存,因此同样的数据尽量只存一次,离散化宁可每次用std::lower_bound()。

    低级错误:
    1.$log$维护老的权值,而不是离散化以后的新权值;
    2.先进行线段树合并再并查集合并,不然并查集Find()的时候回返回同一个点;
    3.离散化的时候vector是从$0$开始存的,因此最后通过离散的权值求原来的权值,应该是$w[b-1]$而不是$w[b]$;
    4.单点修改的时候,原来的$val$值不一定是$1$。

    优化:
    1.在进行3、4操作时,如果查找到对应区间的元素个数是$0$,那么后面两个操作可以省掉;
    2.在区间查询query(),区间修改删除clear()时,如果当前区间的元素个数是$0$,那么不需要再往下递归。

      1 #include<cmath>
      2 #include<cstdio>
      3 #include<vector>
      4 #include<bits/stl_algo.h>
      5 #include<bits/localefwd.h>
      6 inline int getint() {
      7     char ch;
      8     while(!isdigit(ch=getchar()));
      9     int x=ch^'0';
     10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     11     return x;
     12 }
     13 const int M=400001,logM=17;
     14 int data[M][3];
     15 std::vector<int> w;
     16 class DisjointSet {
     17     private:
     18         int anc[M];
     19     public:
     20         DisjointSet() {
     21             for(int i=0;i<M;i++) anc[i]=i;
     22         }
     23         int Find(const int x) {
     24             return x==anc[x]?x:anc[x]=Find(anc[x]);
     25         }
     26         void Union(const int x,const int y) {
     27             anc[Find(x)]=Find(y);
     28         }
     29         bool isConnected(const int x,const int y) {
     30             return Find(x)==Find(y);
     31         }
     32 };
     33 DisjointSet s;
     34 class SegmentTree {
     35     private:
     36         static const int nil=0;
     37         static const int SIZE=M*logM;
     38         int val[SIZE],left[SIZE],right[SIZE];
     39         double sum[SIZE];
     40         bool tag[SIZE];
     41         int sz;
     42         int newnode() {
     43             return ++sz;
     44         }
     45         void push_up(const int p) {
     46             val[p]=val[left[p]]+val[right[p]];
     47             sum[p]=sum[left[p]]+sum[right[p]];
     48         }
     49         void push_down(const int p) {
     50             if(!tag[p]) return;
     51             tag[p]=false;
     52             tag[left[p]]=tag[right[p]]=true;
     53             val[left[p]]=val[right[p]]=0;
     54             sum[left[p]]=sum[right[p]]=0;
     55         }
     56     public:
     57         int root[M];
     58         SegmentTree() {
     59             sz=0;
     60             val[nil]=0;
     61             sum[nil]=0;
     62             tag[nil]=false;
     63         }
     64         void insert(int &p,const int b,const int e,const int x) {
     65             p=newnode();
     66             left[p]=right[p]=nil;
     67             tag[p]=false;
     68             if(b==e) {
     69                 val[p]=1;
     70                 sum[p]=log(w[x-1]);
     71                 return;
     72             }
     73             int mid=(b+e)>>1;
     74             if(x<=mid) insert(left[p],b,mid,x);
     75             if(x>mid) insert(right[p],mid+1,e,x);
     76             push_up(p);
     77         }
     78         int merge(const int p1,const int p2) {
     79             if(!p1||!p2) return p1|p2;
     80             push_down(p1);
     81             push_down(p2);
     82             val[p1]+=val[p2];
     83             sum[p1]+=sum[p2];
     84             left[p1]=merge(left[p1],left[p2]);
     85             right[p1]=merge(right[p1],right[p2]);
     86             return p1;
     87         }
     88         void modify(int &p,const int b,const int e,const int x,const int y) {
     89             if(!p) p=newnode();
     90             if(b==e) {
     91                 val[p]+=y;
     92                 sum[p]=log(w[b-1])*val[p];
     93                 return;
     94             }
     95             push_down(p);
     96             int mid=(b+e)>>1;
     97             if(x<=mid) modify(left[p],b,mid,x,y);
     98             if(x>mid) modify(right[p],mid+1,e,x,y);
     99             push_up(p);
    100         }
    101         int query(const int p,const int b,const int e,const int l,const int r) {
    102             if(!val[p]) return 0;
    103             if((b==l)&&(e==r)) return val[p];
    104             push_down(p);
    105             int mid=(b+e)>>1,ret=0;
    106             if(l<=mid) ret+=query(left[p],b,mid,l,std::min(mid,r));
    107             if(r>mid) ret+=query(right[p],mid+1,e,std::max(mid+1,l),r);
    108             return ret;
    109         }
    110         void clear(const int p,const int b,const int e,const int l,const int r) {
    111             if(!val[p]) return;
    112             if((b==l)&&(e==r)) {
    113                 val[p]=0;
    114                 sum[p]=0;
    115                 tag[p]=true;
    116             }
    117             push_down(p);
    118             int mid=(b+e)>>1;
    119             if(l<=mid) clear(left[p],b,mid,l,std::min(mid,r));
    120             if(r>mid) clear(right[p],mid+1,e,std::max(mid+1,l),r);
    121             push_up(p);
    122         }
    123         void modify_less(int &p,const int b,const int e,const int x) {
    124             int d=query(p,b,e,b,x-1);
    125             if(!d) return;
    126             modify(p,b,e,x,d);
    127             clear(p,b,e,b,x-1);
    128         }
    129         void modify_greater(int &p,const int b,const int e,const int x) {
    130             int d=query(p,b,e,x+1,e);
    131             if(!d) return;
    132             modify(p,b,e,x,d);
    133             clear(p,b,e,x+1,e);
    134         }
    135         int find_kth(const int p,const int b,const int e,const int k) {
    136             if(b==e) return w[b-1];
    137             push_down(p);
    138             int mid=(b+e)>>1;
    139             if(val[left[p]]>=k) return find_kth(left[p],b,mid,k);
    140             return find_kth(right[p],mid+1,e,k-val[left[p]]);
    141         }
    142         bool cmp_product(const int x,const int y) {
    143             return sum[x]>sum[y];
    144         }
    145         int size(const int x) {
    146             return val[x];
    147         }
    148 };
    149 SegmentTree t;
    150 int main() {
    151     int m=getint();
    152     for(int i=0;i<m;i++) {
    153         int &c=data[i][0]=getint();
    154         data[i][1]=getint();
    155         if(c!=1&&c!=7) data[i][2]=getint();
    156         if(c==1) w.push_back(data[i][1]);
    157         if(c==3||c==4) w.push_back(data[i][2]);
    158     }
    159     std::sort(w.begin(),w.end());
    160     int n=std::unique(w.begin(),w.end())-w.begin();
    161     w.resize(n);
    162     for(int i=0,cnt=0;i<m;i++) {
    163         int &c=data[i][0];
    164         switch(c) {
    165             case 1: {
    166                 cnt++;
    167                 int x=std::lower_bound(w.begin(),w.end(),data[i][1])-w.begin()+1;
    168                 t.insert(t.root[cnt],1,n,x);
    169                 break;
    170             }
    171             case 2: {
    172                 int &a=data[i][1],&b=data[i][2];
    173                 if(s.isConnected(a,b)) continue;
    174                 t.root[s.Find(b)]=t.merge(t.root[s.Find(b)],t.root[s.Find(a)]);
    175                 s.Union(a,b);
    176                 break;
    177             }
    178             case 3: {
    179                 int &a=data[i][1],x=lower_bound(w.begin(),w.end(),data[i][2])-w.begin()+1;
    180                 t.modify_less(t.root[s.Find(a)],1,n,x);
    181                 break;
    182             }
    183             case 4: {
    184                 int &a=data[i][1],x=lower_bound(w.begin(),w.end(),data[i][2])-w.begin()+1;
    185                 t.modify_greater(t.root[s.Find(a)],1,n,x);
    186                 break;
    187             }
    188             case 5: {
    189                 int &a=data[i][1],&k=data[i][2];
    190                 printf("%d
    ",t.find_kth(t.root[s.Find(a)],1,n,k));
    191                 break;
    192             }
    193             case 6: {
    194                 int &a=data[i][1],&b=data[i][2];
    195                 printf("%d
    ",t.cmp_product(t.root[s.Find(a)],t.root[s.Find(b)]));
    196                 break;
    197             }
    198             case 7: {
    199                 int &a=data[i][1];
    200                 printf("%d
    ",t.size(t.root[s.Find(a)]));
    201                 break;
    202             }
    203         }
    204     }
    205     return 0;
    206 }
  • 相关阅读:
    Django之F和Q查询
    Django 调试models 输出的SQL语句 定位查看结果
    win10无法开启网络发现怎么办 如何启用网络发现
    关系型数据库和非关系数据库区别
    SSM项目——乐淘商城话述1.0
    微服务简历V1.0
    Spring cloud 项目———酷派手机商城 (话术)1.0
    第四轮面试
    第三轮面试
    02技能点面试题汇总
  • 原文地址:https://www.cnblogs.com/skylee03/p/7448212.html
Copyright © 2020-2023  润新知