2018.3.10

1、

[cdq分治三维偏序]炉石传说加强版

有n朵花,每朵花有三个属性:花形(s)、颜色(c)、气味(m),又三个整数表示。

现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量。

定义一朵花A比另一朵花B要美丽,当且仅当Sa>=Sb,Ca>=Cb,Ma>=Mb。显然,两朵花可能有同样的属性。需要统计出评出每个等级的花的数量。

输入格式
第一行为N,K (1 <= N <= 100,000, 1 <= K <= 200,000 ), 分别表示花的数量和最大属性值。

以下N行,每行三个整数si, ci, mi (1 <= si, ci, mi <= K),表示第i朵花的属性

输出格式
包含N行,分别表示评级为0…N-1的每级花的数量。

input

10 3
3 3 3
2 3 3
2 3 1
3 1 1
3 1 2
1 3 1
1 1 2
1 2 2
1 3 2
1 2 1
output

3
1
3
0
1
0
1
0
0
1
数据规模与约定
1 <= N <= 100,000, 1 <= K <= 200,000 .
数据生成:闵梓轩

时间限制:1s

空间限制:256MB

裸的三维偏序。
按照入门的思想,一维sort排掉,一维任然用归并,同时归并的时候我们考虑处理第三位。
根据cdq排序的性质,只有左边会影响右边,那么我们每次只要把左边的加入树状数组即可。
但是树状数组的大小<=200000这里就要考虑一个细节,每次分治的时候我们我们要额外开个数组存每次加入树状数组的权值。再一个个删除,否则会t。
那么这道题就圆满了。
(值得一提的是,我树状数组find的时候,顺手写了个x<=n,然后大力GG)

#include<bits/stdc++.h>
using namespace std;
int n,ans[101000];
int anss[101000];
int tr[201000],k;
int ad[101000];
int lowbit(int x) {return x&-x;}
struct point{
    int a,b,c,id;
}a[101000];
int read() { 
    bool flag = true; int num = 0;char c = getchar(); 
    for(;c < '0' || c > '9';c = getchar())if(c == '-') flag = false; 
    for(;c >= '0' && c <= '9';c = getchar()) num = ( num << 3 ) + ( num << 1 ) + c - 48; 
    if(flag) return num;  else return -num; 
}
bool mycup( point x,point y ){return x.a<y.a||(x.a==y.a&&x.b<y.b)||(x.a==y.a&&x.b==y.b&&x.c<y.c);}
void init(){
    n = read();k = read();
    for(int i = 1;i <= n;++i) a[i].a = read(),a[i].b = read(),a[i].c = read(),a[i].id = i;
    sort(a + 1,a + n +1,mycup);
    return;
}
bool same(point x,point y){
    return x.a==y.a&&x.b==y.b&&x.c==y.c;
}
void first(){
    point t;int cnt = 1;
    for(int i = n;i; -- i){
        if(same(t,a[i])){
            ans[a[i].id] += cnt;
            ++ cnt;
        } else {
            t = a[i];
            cnt = 1;
        }
    }
}
int find (int x){
    int sum = 0;
    while(x > 0){
        sum += tr[x];
        x -= lowbit(x);
    }
    return sum;
}
void insert(int x,int num){
    while(x <= k){
        tr[x] += num;
        x += lowbit(x);
    }
    return;
}
point tmp[101000];
void cdq(int l,int r){
    if(l  == r) return;
    int m = (l + r) / 2;
    cdq(l,m);cdq(m + 1,r);
    int p = l,q = m + 1,t = 0,o = 0;
    while( p <= m && q <= r)
      if(a[p].b <= a[q].b)  insert(a[p].c,1) , tmp[++t] = a[p] , ad[++o] = a[p++].c;
       else ans[ a[q].id ]+= find(a[q].c) , tmp[++t] = a[q++]; 
    while(p <= m) tmp[++t] = a[p++];
    while(q <= r) ans[ a[q].id ]+= find(a[q].c) , tmp[++t] = a[q++];
    for(int i = 1;i <= t;++i) a[l + i - 1] = tmp[i];
    for(int i = 1;i <= o;++i) insert(ad[i],-1);
    return;
}
void print(){
    for(int i = 1;i <= n;++i) anss[ans[i]]++;
    for(int i = 0;i <= n - 1;++i) printf("%d\n",anss[i]);
    return;
}
int main(){
    init();
    first();
    cdq(1,n);
    print();
    return 0;
}

2、

[cdq分治]好朋友的题

题目是这样的:

有一个N*N矩阵,给出一系列的修改和询问,修改是这样的:将(x,y)中的数字加上k,而询问是这样的:求(x1,y1)到(x2,y2)这个子矩阵内所有数字的和。

虽然这么高级的数据结构题mzx这种菜逼当然不会,但是由于dydxh给mzx留了一条没有强制在线的生路,所以mzx决定挑战一下这道题。

输入格式
输入数据第一行为一个正整数N。

接下来不知道多少行,每行第一个数为操作类型,1为修改,2为询问,3为dydxh不屑于考mzx,这个程序该GG了。

对于每个1,有三个参数x,y,k,表示将(x,y)中的数字加上k。

对于每个2,有四个参数x1,y1,x2,y2,表示询问这个子矩阵内的数字的和。

输出格式
对于每个询问操作,输出对应的答案。

input

4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
output

3
5
数据规模与约定
1<=N<=2000000,操作数不超过200000个,操作1中的k为正整数,且不超过10000。

数据生成:闵梓轩

时间限制:1s

空间限制:256MB

三维偏序,第一维是时间(下标),另外两维分别是x坐标,y左边。
然后就和之前那题一模一样了。

#include<bits/stdc++.h>
using namespace std;
int n;
int t,aid;
int ans[2001000];
struct query{
    int x,y,kind,val;//kind=2为加 3为减 
}q[8001000];
struct add{
    int pl,num;
}ad[2001000];
int lowbit(int x) {return x&-x;}
int tr[2001000];
int read() { 
    bool flag = true; int num = 0;char c = getchar(); 
    for(;c < '0' || c > '9';c = getchar())if(c == '-') flag = false; 
    for(;c >= '0' && c <= '9';c = getchar()) num = ( num << 3 ) + ( num << 1 ) + c - 48; 
    if(flag) return num;  else return -num; 
}
void init(){
    n = read();
    int k = 0;
    while(scanf("%d",&k) != EOF ){
        if(k == 1){
            int x , y , v;
            x = read(); y = read(); v = read();
            q[++t].kind = 1; q[t].x = x; q[t].y = y; q[t].val = v; 
        }
        else 
        if(k==2){
            int x1 , y1 , x2 , y2;
            x1 = read(); y1 = read(); x2 = read(); y2 = read();
            q[++t].kind = 2; q[t].x = x1-1; q[t].y = y1-1; q[t].val = ++aid;
            q[++t].kind = 2; q[t].x = x2; q[t].y = y2; q[t].val = aid;          
            q[++t].kind = 3; q[t].x = x1-1; q[t].y = y2; q[t].val = aid; 
            q[++t].kind = 3; q[t].x = x2; q[t].y = y1-1; q[t].val = aid; 
        }
        else break;
    }
    return;
}
int find (int x){
    int sum = 0;
    while(x > 0){
        sum += tr[x];
        x -= lowbit(x);
    }
    return sum;
}
void insert(int x,int num){
    while(x <= n){
        tr[x] += num;
        x += lowbit(x);
    }
    return;
}
query tmp[8001000];
void cdq(int l,int r){
    if(l  == r) return;
    int m = (l + r) / 2;
    cdq(l,m);cdq(m + 1,r);
    int i = l,j = m + 1,t_new = 0,o = 0,sum = 0;
    while( i <= m && j <= r)
     if(q[i].x <= q[j].x){
        if(q[i].kind == 1) insert(q[i].y,q[i].val) , ad[++o].pl = q[i].y , ad[o].num = q[i].val;
        tmp[++t_new] = q[i++];
     }
     else{
        if(q[j].kind == 2) ans[q[j].val] += find(q[j].y);
        if(q[j].kind == 3) ans[q[j].val] -= find(q[j].y); 
        tmp[++t_new] = q[j++];
     }
    while(i <= m) tmp[++t_new] = q[i++];
    while(j <= r) {
        if(q[j].kind == 2) ans[q[j].val] += find(q[j].y);
        if(q[j].kind == 3) ans[q[j].val] -= find(q[j].y);
        tmp[++t_new] = q[j++];
    }
    for(int i = 1;i <= t_new;++i) q[l + i - 1] = tmp[i];
    for(int i = 1;i <= o;++i) insert(ad[i].pl,-ad[i].num);
    return;
}
void print(){
    for(int i = 1;i <= aid;++i) 
     printf("%d\n",ans[i]);
    return;
}
int main(){
    init();
    cdq(1,t);
    print();
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值