打了一场cf….菜的抠脚
http://blog.csdn.net/a1035719430/article/details/79502382
昨天学的cdq分治。在很多偏序问题cdq分治都可以起到很好的效果(代替高级数据结构)
cdq—>
1、入门题:[cdq分治二维偏序]炉石传说
背景
自从掉入了炉石坑之后,mzx天天在想着自己的卡组收藏,终于有一天,他想到一个问题:我的卡组里面的随从质量都是些什么级别的?于是,他决定编程解决一下这个问题。
题目描述
mzx的卡组收藏中一共有n张随从牌,为了准确的描述这个问题,mzx定义一个随从的身材被另一个随从“完爆”当且仅当该随从的的攻击力和血量都不大于另一个随从,现在,mzx想求出每个随从能够“完爆”的其他随从数。注意,因为mzx是个分卡狂魔,所以他的卡组收藏中不存在两张身材相同的随从牌。
输入格式
输入数据第一行为一个正整数n。
接下来n行,第i+1行两个整数,分别表示第i个随从的攻击力和生命值。输入数据保证不存在两个随从的攻击力和生命值完全相同。
输出格式
输出文件一共i行,第i行表示第i个随从能够完爆的其他随从数。
input
5
1 1
5 1
7 1
3 3
5 5
output
0
1
2
1
3
数据规模与约定
n≤200000,0≤ai,bi≤1000000000.
注意并不只是数据量加强了。
题面数据生成:闵梓轩
时间限制:1s
空间限制:256MB
#include<bits/stdc++.h>
using namespace std;
int n,ans[201000];
struct point{
int a,b,id;
}a[201000];
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);}
void init(){
n = read();
for(int i = 1;i <= n;++i) a[i].a = read(),a[i].b = read(),a[i].id = i;
sort(a + 1,a + n +1,mycup);
return;
}
point tmp[201000];
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;
int sum=0;
while( p <= m && q <= r)
if(a[p].b <= a[q].b) sum++ ,tmp[++t] = a[p++];
else ans[a[q].id] += sum , tmp[++t] = a[q++];
while(p <= m) tmp[++t] = a[p++];
while(q <= r) ans[a[q].id] += sum , tmp[++t] = a[q++];
for(int i = 1;i <= t;++i) a[l+i-1] = tmp[i];
return;
}
void print(){
for(int i = 1;i <= n;++i)
printf("%d\n",ans[i]);
return;
}
int main(){
init();
cdq(1,n);
print();
return 0;
}
2、
[cdq分治二维偏序]数列求和
本题作为分治的练习题,当然可以用其他模板水过,希望珍惜练习的机会
题目描述
假设有一列数 {Ai }(1 ≤ i ≤ n) ,支持如下两种操作:
(1)将 A k 的值加 D 。( k, D 是输入的数)
(2) 输出 A s +A s+1 +…+A t 。( s, t 都是输入的数, S ≤ T )
根据操作要求进行正确操作并输出结果。
输入格式
输入文件第一行一个整数 n(0<=n<=100000) ;
第二行为 n 个整数,表示 {A i } 的初始值。
第三行为一个整数 m(0<=m<=150000) ,表示操作数。 下接 m 行,每行描述一个操作,有如下两种情况:
ADD k d ( 表示将 A k 加 d , 1<=k<=n , d 为整数 )
SUM s t (表示输出 A s +…+A t )
输出格式
对于每一个 SUM 提问,输出结果
样例数据
input
4
1 4 2 3
3
SUM 1 3
ADD 2 50
SUM 2 3
output
7
56
数据规模与约定
时间限制:1s1s
空间限制:256MB
#include<bits/stdc++.h>
using namespace std;
int n,t_q,aid,m;
int ans[151000];
struct queryy{
int pl,kind,v;
}query[501000];
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 check( int a, int b ){
if(query[a].pl != query[b].pl) return query[a].pl < query[b].pl;
else return query[a].kind==1;
}
void init(){
n = read();
for(int i = 1;i <= n;++i){
int x = read();
query[++t_q].pl = i;
query[t_q].v = x;
query[t_q].kind = 1;
}
m = read();
for(int i = 1;i <= m;++i){
char c=0;
while(c != 'S' && c != 'A') c = getchar();
if(c == 'A'){
int x = read(),xx=read();
query[++t_q].pl = x;
query[t_q].v = xx ;
query[t_q].kind = 1;
}
else{
int l=read(),r=read();
query[++t_q].pl = l-1;
query[t_q].v = ++aid;
query[t_q].kind = 2;
query[++t_q].pl = r;
query[t_q].v = aid;
query[t_q].kind = 3;
}
}
}
queryy tmp[501000];
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;
int sum = 0,t=0;
while( p <= m && q <= r ){
if( check(p,q) ){
if(query[p].kind == 1) sum += query[p].v;
tmp[++t] = query[p++];
}
else{
if(query[q].kind == 2) ans[ query[q].v ] -= sum;
if(query[q].kind == 3) ans[ query[q].v ] += sum;
tmp[++t] = query[q++];
}
}
while( p <= m ) tmp[++t] = query[p++];
while( q <= r ) {
if(query[q].kind == 2) ans[query[q].v] -= sum;
if(query[q].kind == 3) ans[query[q].v] += sum;
tmp[++t] = query[q++];
}
for(int i = 1;i <= t;++i) query[l+i-1]=tmp[i];
return;
}
void print(){
for(int i = 1;i <= aid;++i) printf("%d\n",ans[i]);
return;
}
int main(){
init();
cdq(1,t_q);
print();
return 0;
}