• 初识CDQ分治


    [BZOJ 1176:单点修改,查询子矩阵和]:

    1176: [Balkan2007]Mokia

    Time Limit: 30 Sec  Memory Limit: 162 MB
    Submit: 2005  Solved: 894
    [Submit][Status][Discuss]

    Description

    维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.

    Input

    第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

    接下来每行为一下三种输入之一(不包含引号):

    "1 x y a"

    "2 x1 y1 x2 y2"

    "3"

    输入1:你需要把(x,y)(第x行第y列)的格子权值增加a

    输入2:你需要求出以左下角为(x1,y1),右上角为(x2,y2)的矩阵内所有格子的权值和,并输出

    输入3:表示输入结束

    Output

    对于每个输入2,输出一行,即输入2的答案

    Sample Input

    0 4
    1 2 3 3
    2 1 1 3 3
    1 2 2 2
    2 2 2 3 4
    3

    Sample Output

    3
    5

    HINT

    保证答案不会超过int范围

    Source

    分析:

    第一道CDQ分治的题目TAT...

    查询的限制——序

    对于一个数据结构题而言(或者需要运用数据结构的地方),我们无非就是做两件操作,一是修改,二是查询 
    对于修改而言,有插入删除变更(其实等价于删除再插入)这几种方式 
    那么查询的本质是什么呢 
    我们思考所遇到过的数据结构题,可以发现查询实际上就在做一件事情: 
    符合本次查询的限制的修改对答案产生的效果合并起来 
    满足这种限制通常表现为一种的要求,并且这种序是广义的,符合限制的操作往往是按某种序(或多种序)排序后的操作的前缀 
    通常来说,查询一定有时间上的限制,也就是要求考虑发生在某个时刻之前的所有查询,对于一个问题而言,假如所有查询要求的发生时刻相同,那这就是一个静态查询问题,如果要求发生的时刻随着查询而变,那这就是一个动态修改问题,动态修改问题较静态查询而言复杂很多,往往需要高级数据结构,可持久化等手段,而静态查询简单很多,例如时间倒流,twopointers之类的方法都是很好的选择

    我理解的CDQ分治就是通过离线去掉时间的限制(或者某一维的限制),把动态修改问题转化为静态查询问题...

    对于这道题来说,我们可以把查询操作分为4个询问前缀和的操作...

    我们把所有的操作按照x排序,那么我们查询的时候维护y的树状数组就可以...这样达到了降维的目的...

    我们把操作按照x排序,然后对于当前操作区间[l,r],可以应用分治的思想,把区间按照时间为关键字分为[l,mid]和[mid+1,r]两个区间(在两个区间内x依然有序),对于区间内部的修改操作对查询操作的影响,这是一个相同的子问题,所以我们递归解决即可...我们只需要处理的就是[l,mid]中的修改操作对[mid+1,r]中的查询操作的影响...这个树状数组处理即可...

    代码:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 //by NeighThorn
      6 using namespace std;
      7 //大鹏一日同风起,扶摇直上九万里 
      8 
      9 const int maxn=2000000+5,maxm=200000+5;
     10 
     11 struct M{
     12     int x,y,val,pos,ans;
     13     M() {}
     14     M(int a,int b,int c,int d);
     15 }q[maxm],q2[maxm];
     16 
     17 int n,m,op,T,tr[maxn],tim[maxn];
     18 
     19 M :: M(int a=0,int b=0,int c=0,int d=0){
     20     x=a,y=b,val=c,pos=d,ans=0;
     21 }
     22 
     23 inline void insert(int x,int y){
     24     for(;x<=n;x+=x&(-x)){
     25         if(tim[x]!=T)
     26             tr[x]=0;
     27         tim[x]=T,tr[x]+=y;
     28     }
     29 }
     30 
     31 inline int query(int x){
     32     int res=0;
     33     for(;x;x-=x&(-x))
     34         if(tim[x]==T)
     35             res+=tr[x];
     36     return res;
     37 }
     38 
     39 inline bool cmp1(M a,M b){
     40     return a.x<b.x;
     41 }
     42 
     43 inline bool cmp2(M a,M b){
     44     return a.pos<b.pos;
     45 }
     46 
     47 inline void CDQ(int l,int r){
     48     if(l==r)
     49         return;
     50     int mid=(l+r)>>1,l1=l,l2=mid+1;
     51     for(int i=l;i<=r;i++){
     52         if(q[i].pos<=mid)
     53             q2[l1++]=q[i];
     54         else
     55             q2[l2++]=q[i];
     56     }
     57     memcpy(q+l,q2+l,sizeof(q[0])*(r-l+1));CDQ(l,mid);
     58     int j=l;T++;
     59     for(int i=mid+1;i<=r;i++){
     60         for(;q[j].x<=q[i].x&&j<=mid;j++)
     61             if(q[j].val!=20010106)
     62                 insert(q[j].y,q[j].val);
     63         if(q[i].val==20010106)
     64             q[i].ans+=query(q[i].y);
     65     }
     66     CDQ(mid+1,r);
     67     l1=l,l2=mid+1;
     68     for(int i=l;i<=r;i++){
     69         if((q[l1].x<q[l2].x&&l1<=mid)||l2>r)
     70             q2[i]=q[l1++];
     71         else
     72             q2[i]=q[l2++];
     73     }
     74     memcpy(q+l,q2+l,sizeof(q[0])*(r-l+1));
     75 }
     76 
     77 signed main(void){
     78     int l,s,x,y;m=0;
     79     scanf("%d%d",&n,&n);
     80     while(scanf("%d",&op)&&op!=3){
     81         if(op==1)
     82             scanf("%d%d%d",&x,&y,&s),q[++m]=M(x,y,s,m);
     83         else
     84             scanf("%d%d%d%d",&l,&s,&x,&y),
     85             q[++m]=M(l-1,s-1,20010106,m),
     86             q[++m]=M(l-1,y  ,20010106,m),
     87             q[++m]=M(x  ,s-1,20010106,m),
     88             q[++m]=M(x  ,y  ,20010106,m);
     89     }
     90     sort(q+1,q+m+1,cmp1);CDQ(1,m);sort(q+1,q+m+1,cmp2);
     91     for(int i=1,lala;i<=m;i++)
     92         if(q[i].val==20010106){
     93             lala =q[i++].ans;
     94             lala-=q[i++].ans;
     95             lala-=q[i++].ans;
     96             lala+=q[i  ].ans;
     97             printf("%d
    ",lala);
     98         }
     99     return 0;
    100 }//Cap ou pas cap. Cap.
    View Code

     

    [BZOJ 3163:背包问题]:

    3163: [Heoi2013]Eden的新背包问题

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 382  Solved: 252
    [Submit][Status][Discuss]

    Description

    “寄没有地址的信,这样的情绪有种距离,你放着谁的歌曲,是怎样的心心静,能不能说给我听。”
    失忆的Eden总想努力地回忆起过去,然而总是只能清晰地记得那种思念的感觉,却不能回忆起她的音容笑貌。 记忆中,她总是喜欢给Eden出谜题:在 valentine’s day 的夜晚,两人在闹市中闲逛时,望着礼品店里精巧玲珑的各式玩偶,她突发奇想,问了 Eden这样的一个问题:有n个玩偶,每个玩偶有对应的价值、价钱,每个玩偶都可以被买有限次,在携带的价钱m固定的情况下,如何选择买哪些玩偶以及每个玩偶买多少个,才能使得选择的玩偶总价钱不超过m,且价值和最大。众所周知的,这是一个很经典的多重背包问题,Eden很快解决了,不过她似乎因为自己的问题被飞快解决感到了一丝不高兴,于是她希望把问题加难:多次 询问,每次询问都将给出新的总价钱,并且会去掉某个玩偶(即这个玩偶不能被选择),再问此时的多重背包的答案(即前一段所叙述的问题)。  
    这下Eden 犯难了,不过Eden不希望自己被难住,你能帮帮他么?  

    Input


    第一行一个数n,表示有n个玩偶,玩偶从0开始编号 
    第二行开始后面的 n行,每行三个数 ai, bi, c i,分别表示买一个第i个玩偶需
    要的价钱,获得的价值以及第i个玩偶的限购次数。 
    接下来的一行为q,表示询问次数。 
    接下来q行,每行两个数di. ei表示每个询问去掉的是哪个玩偶(注意玩偶从0开始编号)以及该询问对应的新的总价钱数。(去掉操作不保留,即不同询问互相独立) 

    Output

     
    输出q行,第i行输出对于第 i个询问的答案。 

    Sample Input

    5
    2 3 4
    1 2 1
    4 1 2
    2 1 1
    3 2 3
    5
    1 10
    2 7
    3 4
    4 8
    0 5


    Sample Output

    13
    11
    6
    12
    4


    HINT

    一共五种玩偶,分别的价钱价值和限购次数为 (2,3,4), (1,2,1), (4,1,2), (2,1,1),(3,2,3)。五个询问,以第一个询问为例。第一个询问表示的是去掉编号为1的玩偶,且拥有的钱数为10时可以获得的最大价值,则此时剩余玩偶为(2,3,4),(4,1,2),(2,1,1),(3,2,3),若把编号为0的玩偶买4个(即全买了),然后编号为3的玩偶买一个,则刚好把10元全部花完,且总价值为13。可以证明没有更优的方案了。注意买某种玩偶不一定要买光。

    100. 数据满足1 ≤ n ≤ 1000, 1 ≤ q ≤ 3*105 , 1 ≤  a

    i、bi、c i ≤ 100, 0 ≤ d i < n,  0  ≤ei ≤ 1000。 

    Source

     

    分析:

    对于删除物品分治...

    我们定义CDQ(l,r)为删除[l,r]这个区间的物品的dp值,那么递归到[l,l]的时候就可以更新答案了...

    怎么计算...因为[l,mid]的dp值一定包含了[mid+1,r]之间的物品,所以我们可以用[mid+1,r]之间的物品更新dp值之后传入[l,mid]进行计算,同理,用[l,mid]的物品更新dp值然后传入[mid+1,r]进行计算...

    其实为了保证复杂度要用单调队列优化背包...但是这题数据水...我很懒...

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 //by NeighThorn
     6 using namespace std;
     7 //大鹏一日同风起,扶摇直上九万里
     8 
     9 const int maxn=1000+5,maxq=300000+5;
    10 
    11 int n,m,cnt,v[maxq],co[maxn],hd[maxn],ans[maxq],pos[maxq],nxt[maxq],val[maxn],num[maxn],f[15][maxn];
    12 
    13 inline void add(int s,int x,int y){
    14     pos[cnt]=y;v[cnt]=s;nxt[cnt]=hd[x];hd[x]=cnt++;
    15 }
    16 
    17 inline void dp(int *f,int x){
    18     for(int i=1;i<=num[x];i++)
    19         for(int j=maxn-5;j>=co[x];j--)
    20             f[j]=max(f[j],f[j-co[x]]+val[x]);
    21 }
    22 
    23 inline void CDQ(int l,int r,int d){
    24     if(l==r){
    25         for(int i=hd[l];i!=-1;i=nxt[i])
    26             ans[pos[i]]=f[d-1][v[i]];
    27         return;
    28     }
    29     int mid=(l+r)>>1;
    30     for(int i=0;i<maxn;i++)
    31         f[d][i]=f[d-1][i];
    32     for(int i=mid+1;i<=r;i++)
    33         dp(f[d],i);
    34     CDQ(l,mid,d+1);
    35     for(int i=0;i<maxn;i++)
    36         f[d][i]=f[d-1][i];
    37     for(int i=l;i<=mid;i++)
    38         dp(f[d],i);
    39     CDQ(mid+1,r,d+1);
    40 }
    41 
    42 signed main(void){
    43     scanf("%d",&n);cnt=0;
    44     memset(hd,-1,sizeof(hd));
    45     for(int i=1;i<=n;i++)
    46         scanf("%d%d%d",&co[i],&val[i],&num[i]);
    47     scanf("%d",&m);
    48     for(int i=1,x,y;i<=m;i++)
    49         scanf("%d%d",&x,&y),add(y,x+1,i);
    50     CDQ(1,n,1);
    51     for(int i=1;i<=m;i++)
    52         printf("%d
    ",ans[i]);
    53     return 0;
    54 }//Cap ou pas cap. Cap.
    View Code

    [BZOJ 3237: 无向图是否联通]:

    3237: [Ahoi2013]连通图

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 1155  Solved: 396
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    4 5
    1 2
    2 3
    3 4
    4 1
    2 4
    3
    1 5
    2 2 3
    2 1 2

    Sample Output

    Connected
    Disconnected
    Connected

    HINT

    N<=100000 M<=200000 K<=100000

    Source

    分析:

    一开始想的是CDQ(l,r)代表的是删掉[l,r]这一整段区间的边无向图的状态,但是发现酱紫是不行滴...

    然后我们发现我们可以对query进行分治,CDQ(l,r)代表的是去掉[l,r]这段询问的边无向图的状态...我们用并查集来维护...

    学习到一个新的方法...用栈来维护并查集的压缩过程,这样可以回溯...

    因为并查集没有按秩合并...所以被YSQ吐槽为“叽里咕噜滚雪球式并查集”...( ̄_ ̄|||)...

    好吧...按秩合并确实快...4s和12s的差距TAT...

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 //by NeighThorn
     6 using namespace std;
     7 //大鹏一日同风起,扶摇直上九万里 
     8 
     9 const int maxn=100000+5,maxm=200000+5;
    10 
    11 int n,m,Q,T,tail,fa[maxn],ans[maxn],stk[maxn*300],vis[maxm];
    12 
    13 struct M{
    14     int num,id[7];
    15 }q[maxn];
    16 
    17 struct G{
    18     int x,y;
    19 }e[maxm];
    20 
    21 inline int find(int x){
    22     if(fa[x]==x)
    23         return x;
    24     stk[++tail]=x;stk[++tail]=fa[x];
    25     return fa[x]=find(fa[x]);
    26 }
    27 
    28 inline void merge(int x,int y){
    29     int fx=find(x),fy=find(y);
    30     if(fx!=fy)
    31         stk[++tail]=fx,stk[++tail]=fx,fa[fx]=fy;
    32 }
    33 
    34 inline void CDQ(int l,int r){
    35     int mid=(l+r)>>1,lala=tail;
    36     if(l==r){
    37         for(int i=1;i<=q[l].num&&ans[l];i++)
    38             if(find(e[q[l].id[i]].x)!=find(e[q[l].id[i]].y))
    39                 ans[l]=0;
    40         while(lala!=tail)
    41             fa[stk[tail-1]]=stk[tail],tail-=2;
    42         return;
    43     }T++;
    44     for(int i=l;i<=mid;i++)
    45         for(int j=1;j<=q[i].num;j++)
    46             vis[q[i].id[j]]=T;
    47     for(int i=mid+1;i<=r;i++)
    48         for(int j=1;j<=q[i].num;j++)
    49             if(vis[q[i].id[j]]!=T)
    50                 merge(e[q[i].id[j]].x,e[q[i].id[j]].y);
    51     CDQ(l,mid);T++;
    52     while(lala!=tail)
    53         fa[stk[tail-1]]=stk[tail],tail-=2;
    54     for(int i=mid+1;i<=r;i++)
    55         for(int j=1;j<=q[i].num;j++)
    56             vis[q[i].id[j]]=T;
    57     for(int i=l;i<=mid;i++)
    58         for(int j=1;j<=q[i].num;j++)
    59             if(vis[q[i].id[j]]!=T)
    60                 merge(e[q[i].id[j]].x,e[q[i].id[j]].y);
    61     CDQ(mid+1,r);
    62     while(lala!=tail)
    63         fa[stk[tail-1]]=stk[tail],tail-=2;
    64 }
    65 
    66 signed main(void){
    67     scanf("%d%d",&n,&m);
    68     memset(vis,-1,sizeof(vis));
    69     for(int i=1;i<=m;i++)
    70         scanf("%d%d",&e[i].x,&e[i].y);
    71     scanf("%d",&Q);
    72     for(int i=1;i<=Q;i++){
    73         scanf("%d",&q[i].num);ans[i]=1;
    74         for(int j=1;j<=q[i].num;j++)
    75             scanf("%d",&q[i].id[j]),vis[q[i].id[j]]=0;
    76     }
    77     for(int i=1;i<=n;i++)
    78         fa[i]=i;
    79     for(int i=1;i<=m;i++)
    80         if(vis[i]==-1)
    81             merge(e[i].x,e[i].y);
    82     CDQ(1,Q);
    83     for(int i=1;i<=Q;i++)
    84         ans[i]?puts("Connected"):puts("Disconnected");
    85     return 0;
    86 }//Cap ou pas cap. Cap.
    View Code

    [BZOJ 2001:动态最小生成树]:

    2001: [Hnoi2010]City 城市建设

    Time Limit: 20 Sec  Memory Limit: 162 MB
    Submit: 1129  Solved: 552
    [Submit][Status][Discuss]

    Description

    PS国是一个拥有诸多城市的大国,国王Louis为城市的交通建设可谓绞尽脑汁。Louis可以在某些城市之间修建道路,在不同的城市之间修建道路需要不同的花费。Louis希望建造最少的道路使得国内所有的城市连通。但是由于某些因素,城市之间修建道路需要的花费会随着时间而改变,Louis会不断得到某道路的修建代价改变的消息,他希望每得到一条消息后能立即知道使城市连通的最小花费总和, Louis决定求助于你来完成这个任务。

    Input

    文件第一行包含三个整数N,M,Q,分别表示城市的数目,可以修建的道路个数,及收到的消息个数。 接下来M行,第i+1行有三个用空格隔开的整数Xi,Yi,Zi(1≤Xi,Yi≤n, 0≤Zi≤50000000),表示在城市Xi与城市Yi之间修建道路的代价为Zi。接下来Q行,每行包含两个数k,d,表示输入的第k个道路的修建代价修改为d(即将Zk修改为d)。

    Output

    输出包含Q行,第i行输出得知前i条消息后使城市连通的最小花费总和。

    Sample Input

    5 5 3
    1 2 1
    2 3 2
    3 4 3
    4 5 4
    5 1 5
    1 6
    1 1
    5 3

    Sample Output

    14
    10
    9

    HINT

    【数据规模】 对于20%的数据, n≤1000,m≤6000,Q≤6000。 有20%的数据,n≤1000,m≤50000,Q≤8000,修改后的代价不会比之前的代价低。 对于100%的数据, n≤20000,m≤50000,Q≤50000。

    Source

    分析:

    这道题的思想主要在于通过分治来缩小图的规模,从而降低复杂度...

    我们定义CDQ(l,r)为处理[l,r]的询问...那么这个时候[1,l-1]的边已经固定了...

    有一下两个操作:

    No.1  合并必须边:

    我们把[l,r]的边设为-inf,跑最小生成树,树边就是必须边...(原因自己YY)...

    No.2  删除多余边:

    我们把[l,r]的边设为+inf,跑最小生成树,非树边是多余边...

    然后递归边界为[l,l]这个时候跑最小生成树然后加上合并的权值就是当前的ans...

    讲道理...这题主要是细节...我调了好久...要了数据才过...(好吧其实数据没有什么用...看样例就100了...这没法调啊w(゚Д゚)w)

    代码:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio> 
      5 //by NeighThorn
      6 #define inf 0x3f3f3f3f
      7 using namespace std;
      8 
      9 const int maxn=20000+5,maxm=50000+5;
     10 
     11 int n,m,Q,T,tail,fa[maxn],stk[maxn*1000],ver[20],edg[20],vis[maxm];
     12 
     13 long long ans[maxm],val[20],w[maxm];
     14 
     15 struct M{
     16     int x,y,w,flag,id;
     17     friend bool operator < (M a,M b){
     18         return a.w<b.w;
     19     }
     20 }G[20][maxm],lala[maxm],lalala[maxm];
     21 
     22 struct L{
     23     int id,w;
     24 }q[maxm];
     25 
     26 inline int find(int x){
     27     if(fa[x]==x)
     28         return x;
     29     stk[++tail]=x,stk[++tail]=fa[x];
     30     return fa[x]=find(fa[x]);
     31 }
     32 
     33 inline void merge(int x,int y){
     34     int fx=find(x),fy=find(y);
     35     if(fx!=fy)
     36         stk[++tail]=fx,stk[++tail]=fx,fa[fx]=fy;
     37 }
     38 
     39 inline long long kruskal(int d){
     40     sort(lala+1,lala+edg[d]+1);long long res=0;
     41     for(int i=1;i<=edg[d];i++){
     42         int fx=find(lala[i].x),fy=find(lala[i].y);
     43         if(fx!=fy)
     44             merge(fx,fy),res+=w[lala[i].id],lala[i].flag=1;
     45         else
     46             lala[i].flag=0;
     47     }
     48     return res;
     49 }
     50 
     51 inline void CDQ(int l,int r,int d){
     52     int tmp=tail,ttmp;
     53     if(l==r){
     54         w[q[l].id]=q[l].w;
     55         for(int i=1;i<=edg[d-1];i++)
     56             lala[i]=G[d-1][i],lala[i].w=w[G[d-1][i].id];
     57         ans[l]=kruskal(d-1)+val[d-1];
     58         while(tmp!=tail)
     59             fa[stk[tail-1]]=stk[tail],tail-=2;
     60         return;
     61     }
     62     edg[d]=edg[d-1],val[d]=val[d-1],ver[d]=ver[d-1];
     63     int mid=(l+r)>>1;T++;
     64     for(int i=l;i<=r;i++)
     65         vis[q[i].id]=T;
     66     for(int i=1;i<=edg[d];i++){
     67         lala[i]=G[d-1][i],lala[i].w=w[G[d-1][i].id];
     68         if(vis[G[d-1][i].id]==T)
     69             lala[i].w=-inf;
     70     }
     71     kruskal(d);
     72     while(tmp!=tail)
     73         fa[stk[tail-1]]=stk[tail],tail-=2;
     74     int haha=edg[d];
     75     for(int i=1,j=0;i<=haha;i++){
     76         if(lala[i].flag&&lala[i].w!=-inf)
     77             merge(lala[i].x,lala[i].y),ver[d]--,edg[d]--,val[d]+=w[lala[i].id];
     78         else
     79             lala[i].x=find(lala[i].x),lala[i].y=find(lala[i].y),G[d][++j]=lala[i],G[d][j].w=w[lala[i].id];
     80     }ttmp=tail;
     81     for(int i=1;i<=edg[d];i++){
     82         G[d][i].x=find(G[d][i].x),G[d][i].y=find(G[d][i].y);
     83         lala[i]=G[d][i],lala[i].w=w[G[d][i].id];
     84         if(vis[G[d][i].id]==T)
     85             lala[i].w=inf;
     86     }
     87     kruskal(d);
     88     while(ttmp!=tail)
     89         fa[stk[tail-1]]=stk[tail],tail-=2;
     90     haha=edg[d];
     91     for(int i=1,j=0;i<=haha;i++){
     92         if(!lala[i].flag&&lala[i].w!=inf)
     93             edg[d]--;
     94         else
     95             lala[i].x=fa[lala[i].x],lala[i].y=fa[lala[i].y],G[d][++j]=lala[i];
     96     }
     97     CDQ(l,mid,d+1),CDQ(mid+1,r,d+1);
     98     while(tail!=tmp)
     99         fa[stk[tail-1]]=stk[tail],tail-=2;
    100 }
    101 
    102 signed main(void){
    103     // freopen("in.txt","r",stdin);
    104     // freopen("out.txt","w",stdout);
    105     scanf("%d%d%d",&n,&m,&Q);
    106     memset(vis,0,sizeof(vis));
    107     for(int i=1;i<=m;i++)
    108         scanf("%d%d%d",&G[0][i].x,&G[0][i].y,&G[0][i].w),G[0][i].id=i,w[i]=G[0][i].w;
    109     for(int i=1;i<=Q;i++)
    110         scanf("%d%d",&q[i].id,&q[i].w);
    111     for(int i=1;i<=n;i++)
    112         fa[i]=i;
    113     edg[0]=m,ver[0]=n,CDQ(1,Q,1); 
    114     for(int i=1;i<=Q;i++)
    115         printf("%lld
    ",ans[i]);
    116     return 0;
    117 }//Cap ou pas cap. Cap.
    View Code

    [BZOJ2716 平面最近点]:

    2716: [Violet 3]天使玩偶

    Time Limit: 80 Sec  Memory Limit: 128 MB
    Submit: 1476  Solved: 623
    [Submit][Status][Discuss]

    Description

    Input

    Output

    分析:

    和第一道题目是一样的,只不过是把求和变成了取max...

    首先我们可以以当前询问的点为原点,把平面划分为4个部分,我们首先考虑左下角的点dis[i,j]=x[i]-x[j]+y[i]-y[j]=x[i]+y[i]-(x[j]+y[j])...

    这样我们只需要查询当前点左下角的点x+y最大的点即可,那么还是按照x排序维护y的树状数组...

    那么其他三个区域的点可以对称一下转化为左下角的点...

    但是这题它卡常数...我人帅自带大常数TAT...T死了...

    所以就把O(nlgn)的四个排序改成了四个memcpy...然后就A了QAQ...

    代码:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 //by NeighThorn
      6 #define inf 0x7fffffff
      7 using namespace std;
      8 //大鹏一日同风起,扶摇直上九万里
      9 
     10 const int maxn=1000000+5,maxm=1000000+5; 
     11 
     12 int n,m,T,Max,tr[maxm],tim[maxm],ans[maxm];
     13 
     14 struct M{
     15     int t,x,y,id;
     16     bool operator <(const M &a)const{
     17         if(x!=a.x)
     18             return x<a.x;
     19         return t<a.t;
     20     }
     21 }q[maxn],q2[maxn],l[maxn];
     22 
     23 inline int read(void){
     24     char ch=getchar();int f=1,x=0;
     25     while(!(ch>='0'&&ch<='9')){
     26         if(ch=='-')
     27             f=-1;
     28         ch=getchar();
     29     }
     30     while(ch>='0'&&ch<='9')
     31         x=x*10+ch-'0',ch=getchar();
     32     return f*x;
     33 }
     34 
     35 inline void insert(int x,int y){
     36     for(;x<=Max;x+=x&-x){
     37         /*
     38         if(tim[x]!=T)
     39             tr[x]=-1;
     40         tim[x]=T,tr[x]=max(tr[x],y);
     41         */
     42         if(tim[x]!=T||tr[x]<y)
     43             tr[x]=y,tim[x]=T;
     44     }
     45 }
     46 
     47 inline int query(int x){
     48     int res=-1;
     49     for(;x;x-=x&-x)
     50         if(tim[x]==T)
     51             res=max(tr[x],res);
     52     return res;
     53 }
     54 
     55 /*
     56 inline void CDQ(int l,int r){
     57     if(l==r)
     58         return;
     59     int mid=(l+r)>>1,l1=l,l2=mid+1;
     60     for(int i=l;i<=r;i++){
     61         if(q[i].id<=mid)
     62             q2[l1++]=q[i];
     63         else
     64             q2[l2++]=q[i];
     65     }
     66     for(int i=l;i<=r;i++)
     67         q[i]=q2[i];
     68     CDQ(l,mid);int j=l;T++;
     69     for(int i=mid+1;i<=r;i++){
     70         for(;q[j].x<=q[i].x&&j<=mid;j++)
     71             if(q[j].t==1)
     72                 insert(q[j].y,q[j].x+q[j].y);
     73         if(q[i].t==2){
     74             int lala=query(q[i].y);
     75             q[i].ans=lala==-1?q[i].ans:min(q[i].x+q[i].y-lala,q[i].ans);
     76         }
     77     }
     78     CDQ(mid+1,r);
     79     l1=l,l2=mid+1;
     80     for(int i=l;i<=r;i++){
     81         if((q[l1].x<q[l2].x&&l1<=mid)||l2>r)
     82             q2[i]=q[l1++];
     83         else
     84             q2[i]=q[l2++];
     85     }
     86     for(int i=l;i<=r;i++)
     87         q[i]=q2[i];
     88 }
     89 */
     90 
     91 inline void CDQ(int l,int r){
     92     if(l==r)
     93         return;
     94     int mid=(l+r)>>1,l1=l,l2=mid+1;
     95     CDQ(l,mid),CDQ(mid+1,r);
     96     for(int i=l;i<=r;i++){
     97         if((l1<=mid&&q[l1]<q[l2])||l2>r)
     98             q2[i]=q[l1++];
     99         else
    100             q2[i]=q[l2++];
    101     }
    102     for(int i=l;i<=r;i++)
    103         q[i]=q2[i];
    104     T++;
    105     for(int i=l;i<=r;i++){
    106         if(q[i].t==2&&q[i].id>mid){
    107             int lala=query(q[i].y);
    108             ans[q[i].id]=lala==-1?ans[q[i].id]:min(q[i].x+q[i].y-lala,ans[q[i].id]);
    109         }
    110         else if(q[i].t==1&&q[i].id<=mid)
    111             insert(q[i].y,q[i].x+q[i].y);
    112     }
    113 }
    114 
    115 signed main(void){
    116 //     freopen("in.txt","r",stdin);
    117 //     freopen("out.txt","w",stdout);
    118     n=read(),m=read();Max=0;T=0;m+=n;
    119     for(int i=1;i<=n;i++){
    120         l[i].x=read()+1,l[i].y=read()+1,l[i].id=i,l[i].t=1;
    121         if(l[i].x>Max)
    122             Max=l[i].x;
    123         if(l[i].y>Max)
    124             Max=l[i].y;
    125     }
    126     for(int i=n+1;i<=m;i++){
    127         l[i].t=read(),l[i].x=read()+1,l[i].y=read()+1,l[i].id=i,ans[i]=inf;
    128         if(l[i].x>Max)
    129             Max=l[i].x;
    130         if(l[i].y>Max)
    131             Max=l[i].y;
    132     }
    133     Max++;
    134     
    135     /*
    136     sort(q+1,q+m+1);CDQ(1,m);
    137     for(int i=1;i<=m;i++)
    138         q[i].x=Max-q[i].x;
    139     sort(q+1,q+m+1);CDQ(1,m);
    140     for(int i=1;i<=m;i++)
    141         q[i].y=Max-q[i].y;
    142     sort(q+1,q+m+1);CDQ(1,m);
    143     for(int i=1;i<=m;i++)
    144         q[i].x=-(q[i].x-Max);
    145     sort(q+1,q+m+1);CDQ(1,m);
    146     */
    147     
    148     memcpy(q,l,sizeof(q));
    149     CDQ(1,m);
    150     
    151     memcpy(q,l,sizeof(q));
    152     for(int i=1;i<=m;i++)
    153         q[i].x=Max-q[i].x;
    154     CDQ(1,m);
    155     
    156     memcpy(q,l,sizeof(q));
    157     for(int i=1;i<=m;i++)
    158         q[i].y=Max-q[i].y;
    159     CDQ(1,m);
    160     
    161     memcpy(q,l,sizeof(q));
    162     for(int i=1;i<=m;i++)
    163         q[i].x=Max-q[i].x,q[i].y=Max-q[i].y;
    164     CDQ(1,m);
    165     
    166     for(int i=n+1;i<=m;i++)
    167         if(l[i].t==2)
    168             printf("%d
    ",ans[i]);
    169     return 0;
    170 }//Cap ou pas cap. Cap.
    View Code

    By NeighThorn

  • 相关阅读:
    Hadoop 的版本问题
    SSH 端口转发原理
    KM算法
    最大流算法小结
    pku 2195 KM算法求最小权二分匹配
    SAP(最短增广路算法) 最大流模板
    最大流模板
    pku 1459 最大流 SAP
    pku Drainage Ditches 简单最大流 直接套模板 注意可能有重边
    推荐:吴军 谷歌黑板报 《浪潮之颠》
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6242059.html
Copyright © 2020-2023  润新知