Description
有n 个位置和m 个操作。操作有两种,每次操作如果是1 a b c 的形式,表示往第a 个位置到第b 个位置每个位置加入一个数c。如果操作形如2 a b c 的形式,表示询问从第a 个位置到第b 个位置,第c 大的数是多少。
Solution
树套树的模板题
找矩阵中第k大的数,肯定是用权值线段树维护区间线段树啦!
在JZOJ跑的正常,BZOJ上怎么都过不了TAT。常数不好啊!毕竟是第一次打树套树。
只能之后打CDQ分治的时候去打打了
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
int i,j,k,l,n,m,ans,root[20000005];
int a,b,c,d,num;
struct node{
int l,r,sum,add;
}t[20000005];
void down(int x,int l,int r){
if(l==r)return;
int mid=(l+r)/2;
if(t[x].add){
if(!t[x].l)t[x].l=++num;
if(!t[x].r)t[x].r=++num;
t[t[x].l].add+=t[x].add,t[t[x].r].add+=t[x].add;
t[t[x].l].sum+=(mid-l+1)*t[x].add,t[t[x].r].sum+=(r-mid)*t[x].add;
t[x].add=0;
}
}
void change(int &x,int l,int r,int y,int z){
if(!x)x=++num;
down(x,l,r);
if(l==y&&r==z){
t[x].sum+=r-l+1;t[x].add++;
return;
}
int mid=(l+r)/2;
if(z<=mid)change(t[x].l,l,mid,y,z);
else if(y>mid)change(t[x].r,mid+1,r,y,z);
else{
change(t[x].l,l,mid,y,mid);
change(t[x].r,mid+1,r,mid+1,z);
}
t[x].sum=t[t[x].l].sum+t[t[x].r].sum;
}
void insert(int x,int y,int z){
int l=1,r=n,o=1;
while(l<r){
int mid=(l+r)/2;
change(root[o],1,n,y,z);
if(x<=mid)r=mid,o*=2;else l=mid+1,o=o*2+1;
}
change(root[o],1,n,y,z);
}
int find(int x,int l,int r,int y,int z){
if(!x)return 0;
down(x,l,r);
if(l==y&&r==z){
return t[x].sum;
}
int mid=(l+r)/2;
if(z<=mid)return find(t[x].l,l,mid,y,z);
else if(y>mid)return find(t[x].r,mid+1,r,y,z);
else{
return find(t[x].l,l,mid,y,mid)+find(t[x].r,mid+1,r,mid+1,z);
}
}
int solve(int x,int y,int z){
int l=1,r=n,o=1;
while(l<r){
int mid=(l+r)/2;
int u=find(root[o*2],1,n,y,z);
if(u>=x)r=mid,o*=2;else l=mid+1,o=o*2+1,x-=u;
}
return n-l+1;
}
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
n=read();m=read();
fo(i,1,m){
a=read();b=read();c=read();d=read();
if(a==1){
d=n-d+1;
insert(d,b,c);
}
else{
printf("%d\n",solve(d,b,c));
}
}
}