http://www.lydsy.com/JudgeOnline/problem.php?id=3110
题意:
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
线段树套线段树,外面是权值,每个节点上的线段树是位置,
比如,如果在1~4位置加入5 就是把整个线段树中有5的log个节点,
每个节点的1~4这log区间上++。。。。
然后每次询问的时候,二分答案,
比如权值二分到3就是求1~3中有多少个在询问的区间里,还是log个节点,
每个节点跑log个得到对应区间上的个数总和
这样会tle&& mle,代码如下:
/*
线段树套线段树,外面是权值,每个节点上的线段树是位置,
比如,如果在1~4位置加入5 就是把整个线段树中有5的log个节点,
每个节点的1~4这log区间上++。。。。
然后每次询问的时候,二分答案,
比如权值二分到3就是求1~3中有多少个在询问的区间里,还是log个节点,
每个节点跑log个得到对应区间上的个数总和
*/
#include
#include
#include
#include
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 3e7+10;
const int maxm = 50000*4+10;
int root[maxm],N,Q;
struct pos_Tree{
int lon,ron,add;
unsigned int _size;
void init(){
lon = ron = add = _size = 0;
}
};
class segment_tree{
public:
pos_Tree tree[maxn];LL cnt;
void push_down(int k,int m,int l,int r){
if(tree[k].add == 0) return ;
if(tree[k].lon == 0){
cnt++;tree[k].lon = cnt;//tree[cnt].l = l;tree[cnt].r = (l+r)/2;
tree[cnt]._size = (m-(m/2))*tree[k].add;tree[cnt].add = tree[k].add;
}
else tree[tree[k].lon]._size +=(m-(m/2))*tree[k].add,tree[tree[k].lon].add += tree[k].add;
if(tree[k].ron == 0){
cnt++;tree[k].ron = cnt;//tree[cnt].l = (l+r)/2+1;tree[cnt].r = r;
tree[cnt]._size = (m/2)*tree[k].add;tree[cnt].add = tree[k].add;
}
else tree[tree[k].ron]._size +=(m/2)*tree[k].add,tree[tree[k].ron].add += tree[k].add;
tree[k].add = 0;
}
void push_up(int k,int ln,int rn){
tree[k]._size = tree[ln]._size+tree[rn]._size;
}
void _insert(int &k,int L,int R,int l,int r,int rt){
if(k == 0){
cnt++;tree[cnt].init();k = cnt;//tree[k].l = l;tree[k].r = r;
}
if(L <= l && R >= r){
tree[k].add++;tree[k]._size += r-l+1;
return ;
}
push_down(k,r-l+1,l,r);
int m = (l+r)>>1;
if(m >= L) _insert(tree[k].lon,L,R,lson);
if(m < R) _insert(tree[k].ron,L,R,rson);
push_up(k,tree[k].lon,tree[k].ron);
}
LL query(int k,int L,int R,int l,int r,int rt){
if(l >= L && r <= R){
return tree[k]._size;
}
push_down(k,r-l+1,l,r);
//cout <<" k = "<
int m = (l+r)/2;
LL ans = 0;
if(m >= L && tree[k].lon) ans += query(tree[k].lon,L,R,lson);
if(m < R && tree[k].ron) ans += query(tree[k].ron,L,R,rson);
return ans;
}
}pos_tree;//区间线段树
void build(int l,int r,int rt){
root[rt] = 0;
if(l == r) return ;
int m = (l+r)>>1;
build(lson);
build(rson);
}
void val_insert(int a,int b,int pos,int l,int r,int rt){
if(pos >= l && pos <= r){
pos_tree._insert(root[rt],a,b,1,N,1);
}
if(l == r) return ;
int m = (l+r)>>1;
if(pos <= m) val_insert(a,b,pos,lson);
else val_insert(a,b,pos,rson);
}
int _in(int mid,int l,int r,int rt){
if(l == r && l == mid) return root[rt];
int m = (l+r)>>1;
if(mid <= m) return _in(mid,lson);
else return _in(mid,rson);
}
LL check(int L,int R,int posa,int posb,int l,int r,int rt){
if(L <= l && R >= r){
if(root[rt] == 0) return 0;
LL ans = pos_tree.query(root[rt],posa,posb,1,N,1);
return ans ;
}
LL ans = 0;
int m = (l+r)>>1;
if(m >= L) ans += check(L,R,posa,posb,lson);
if(m < R) ans += check(L,R,posa,posb,rson);
return ans;
}
int bs(int posa,int posb,int c){
int l = 1,r = N,ans = 100000000;
while(l <= r){
int mid = (l+r)>>1;
LL pp = check(1,mid,posa,posb,1,N,1);
if( pp >= c){//1~mid权值中到了c个就是可能得解,多了就缩小范围
if(_in(mid,1,N,1))//mid是否是出现了得权值
ans = min(ans,mid);
r = mid-1;
}
else l = mid+1;
}
return ans;
}
int op,a,b,c;
void sov(){
pos_tree.cnt = 0;
for(int i = 1; i<= Q ; i++){
scanf("%d",&op);
if(op == 1){
scanf("%d%d%d",&a,&b,&c);
if(a > b) swap(a,b);
c = N-c+1;
val_insert(a,b,c,1,N,1);
}
else{
scanf("%d%d%d",&a,&b,&c);
if(a > b) swap(a,b);
printf("%d\n",N-bs(a,b,c)+1);
}
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d",&N,&Q)){
build(1,N,1);
sov();
}
return 0;
}
/*
7 100
1 1 5 2
1 2 7 3
1 3 5 2
1 1 1 1
2 1 3 2
2 1 3 3
2 1 3 7
2 1 7 5
2 1 7 7
2 2 3 2
2 1 1 1
2 1 1 2
2 3 5 3
2 3 4 5
2 1 5 2
2 2 7 2
2 3 5 2
2 2 2 1
*/
改成树状数组,mle问题解决,时间复杂度仍然有logloglog
#include
#include
#include
#include
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 3e7+10;
const int maxm = 50000+10;
int root[maxm],N,Q;
struct pos_Tree{
int lon,ron,add;
unsigned int _size;
void init(){
lon = ron = add = _size = 0;
}
};
class segment_tree{
public:
pos_Tree tree[maxn];LL cnt;
void push_down(int k,int m,int l,int r){
if(tree[k].add == 0) return ;
if(tree[k].lon == 0){
cnt++;tree[k].lon = cnt;//tree[cnt].l = l;tree[cnt].r = (l+r)/2;
tree[cnt]._size = (m-(m/2))*tree[k].add;tree[cnt].add = tree[k].add;
}
else tree[tree[k].lon]._size +=(m-(m/2))*tree[k].add,tree[tree[k].lon].add += tree[k].add;
if(tree[k].ron == 0){
cnt++;tree[k].ron = cnt;//tree[cnt].l = (l+r)/2+1;tree[cnt].r = r;
tree[cnt]._size = (m/2)*tree[k].add;tree[cnt].add = tree[k].add;
}
else tree[tree[k].ron]._size +=(m/2)*tree[k].add,tree[tree[k].ron].add += tree[k].add;
tree[k].add = 0;
}
void push_up(int k,int ln,int rn){
tree[k]._size = tree[ln]._size+tree[rn]._size;
}
void _insert(int &k,int L,int R,int l,int r,int rt){
if(k == 0){
cnt++;tree[cnt].init();k = cnt;//tree[k].l = l;tree[k].r = r;
}
if(L <= l && R >= r){
tree[k].add++;tree[k]._size += r-l+1;
return ;
}
push_down(k,r-l+1,l,r);
int m = (l+r)>>1;
if(m >= L) _insert(tree[k].lon,L,R,lson);
if(m < R) _insert(tree[k].ron,L,R,rson);
push_up(k,tree[k].lon,tree[k].ron);
}
LL query(int k,int L,int R,int l,int r,int rt){
if(l >= L && r <= R){
return tree[k]._size;
}
push_down(k,r-l+1,l,r);
//cout <<" k = "<
int m = (l+r)/2;
LL ans = 0;
if(m >= L && tree[k].lon) ans += query(tree[k].lon,L,R,lson);
if(m < R && tree[k].ron) ans += query(tree[k].ron,L,R,rson);
return ans;
}
}pos_tree;//Çø¼äÏ߶ÎÊ÷
int lowbit(int x){
return x&(-x);
}
void add(int pos,int a,int b){
for(int i = pos ; i <= N ;i += lowbit(i)){
pos_tree._insert(root[i],a,b,1,N,1);
}
}
LL check(int pos,int posa,int posb){
LL sum = 0;
for(int i = pos; i>0 ;i-=lowbit(i)){
sum += pos_tree.query(root[i],posa,posb,1,N,1);
}
return sum;
}
int bs(int posa,int posb,int k){
int l = 1,r = N;
while(l <= r){
int mid = (l+r)>>1;
LL cm = check(mid,posa,posb);//1~mid
LL cm1 = check(mid-1,posa,posb);//1~mid-1
if(cm >= k && cm1 < k){
return mid;
}
else if(cm >= k) r = mid-1;
else l = mid+1; //cm
}
}
int op,a,b,c;
void sov(){
pos_tree.cnt = 0;
for(int i = 1; i<= Q ; i++){
scanf("%d",&op);
if(op == 1){
scanf("%d%d%d",&a,&b,&c);
c = N-c+1;
if(a > b) swap(a,b);
add(c,a,b);
}
else{
scanf("%d%d%d",&a,&b,&c);
if(a > b) swap(a,b);
printf("%d\n",N-bs(a,b,c)+1);
}
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d",&N,&Q)){
sov();
}
}
超时?不用二分答案,在线段树上,直接判断大的数够不够,不够的话,往左跑看加上多少左边的可以到达要求个,够的话就往右递归,看最小的范围(l==r)时候,ac代码:
/*
线段树套线段树,外面是权值,每个节点上的线段树是位置,
比如,如果在1~4位置加入5 就是把整个线段树中有5的log个节点,
每个节点的1~4这log区间上++。。。。
然后每次询问的时候,
每个节点跑log个得到对应区间上的个数总和
*/
#include
#include
#include
#include
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long LL;
const int maxn = 3e7+10;
const int maxm = 50000*4+10;
int root[maxm],N,Q;
struct pos_Tree{
int lon,ron,add;
unsigned int _size;
void init(){
lon = ron = add = _size = 0;
}
};
class segment_tree{
public:
pos_Tree tree[maxn];LL cnt;
void push_down(int k,int m,int l,int r){
if(tree[k].add == 0) return ;
if(tree[k].lon == 0){
cnt++;tree[k].lon = cnt;//tree[cnt].l = l;tree[cnt].r = (l+r)/2;
tree[cnt]._size = (m-(m/2))*tree[k].add;tree[cnt].add = tree[k].add;
}
else tree[tree[k].lon]._size +=(m-(m/2))*tree[k].add,tree[tree[k].lon].add += tree[k].add;
if(tree[k].ron == 0){
cnt++;tree[k].ron = cnt;//tree[cnt].l = (l+r)/2+1;tree[cnt].r = r;
tree[cnt]._size = (m/2)*tree[k].add;tree[cnt].add = tree[k].add;
}
else tree[tree[k].ron]._size +=(m/2)*tree[k].add,tree[tree[k].ron].add += tree[k].add;
tree[k].add = 0;
}
void push_up(int k,int ln,int rn){
tree[k]._size = tree[ln]._size+tree[rn]._size;
}
void _insert(int &k,int L,int R,int l,int r,int rt){
if(k == 0){
cnt++;tree[cnt].init();k = cnt;//tree[k].l = l;tree[k].r = r;
}
if(L <= l && R >= r){
tree[k].add++;tree[k]._size += r-l+1;
return ;
}
push_down(k,r-l+1,l,r);
int m = (l+r)>>1;
if(m >= L) _insert(tree[k].lon,L,R,lson);
if(m < R) _insert(tree[k].ron,L,R,rson);
push_up(k,tree[k].lon,tree[k].ron);
}
LL query(int k,int L,int R,int l,int r,int rt){
if(l >= L && r <= R){
return tree[k]._size;
}
push_down(k,r-l+1,l,r);
//cout <<" k = "<
int m = (l+r)/2;
LL ans = 0;
if(m >= L && tree[k].lon) ans += query(tree[k].lon,L,R,lson);
if(m < R && tree[k].ron) ans += query(tree[k].ron,L,R,rson);
return ans;
}
}pos_tree;//区间线段树
void build(int l,int r,int rt){
root[rt] = 0;
if(l == r) return ;
int m = (l+r)>>1;
build(lson);
build(rson);
}
void val_insert(int a,int b,int pos,int l,int r,int rt){
if(pos >= l && pos <= r){
pos_tree._insert(root[rt],a,b,1,N,1);
}
if(l == r) return ;
int m = (l+r)>>1;
if(pos <= m) val_insert(a,b,pos,lson);
else val_insert(a,b,pos,rson);
}
LL check(int posa,int posb,int num,int l,int r,int rt){
if(l == r) return l;
int m = (l+r)>>1,ans;
LL n1 = (root[rt*2+1] == 0)?0:pos_tree.query(root[rt*2+1],posa,posb,1,N,1);
if(n1 < num) ans = check(posa,posb,num-n1,lson);
else ans = check(posa,posb,num,rson);
return ans;
}
int op,a,b,c;
void sov(){
pos_tree.cnt = 0;
for(int i = 1; i<= Q ; i++){
scanf("%d",&op);
if(op == 1){
scanf("%d%d%d",&a,&b,&c);
if(a > b) swap(a,b);
val_insert(a,b,c,1,N,1);
}
else{
scanf("%d%d%d",&a,&b,&c);
if(a > b) swap(a,b);
printf("%d\n",check(a,b,c,1,N,1));
}
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d",&N,&Q)){
build(1,N,1);
sov();
}
return 0;
}
/*
7 100
1 1 5 2
1 2 7 3
1 3 5 2
1 1 1 1
2 1 3 2
2 1 3 3
2 1 3 7
2 1 7 5
2 1 7 7
2 2 3 2
2 1 1 1
2 1 1 2
2 3 5 3
2 3 4 5
2 1 5 2
2 2 7 2
2 3 5 2
2 2 2 1
*/