Description
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
Input
第一行N,M
接下来M行,每行形如1 a b c或2 a b c
Output
输出每个询问的结果
Sample Input
2 5
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
1 1 2 1
1 1 2 2
2 1 1 2
2 1 1 1
2 1 2 3
Sample Output
1
2
1
2
1
HINT
【样例说明】
第一个操作 后位置 1 的数只有 1 , 位置 2 的数也只有 1 。 第二个操作 后位置 1
的数有 1 、 2 ,位置 2 的数也有 1 、 2 。 第三次询问 位置 1 到位置 1 第 2 大的数 是
1 。 第四次询问 位置 1 到位置 1 第 1 大的数是 2 。 第五次询问 位置 1 到位置 2 第 3
大的数是 1 。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中abs(c)<=Maxlongint
一道树套树的题
外层是一颗权值线段树
内层是传统的区间线段树
插入:在a-b插入权值c
在外层线段树所有包含权值c的线段中,在其里层的线段树插入线段a-b
询问:在a-b中询问第k大的权值
从外层线段树(权值)开始,如果右孩子的内层线段树在区间a-b中的计数超过k个,显然答案在右孩子,否则在左孩子,以此类推
代码:
</pre><pre name="code" class="cpp">#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
using namespace std;
struct Tree
{
int l,r,lazy,sum;
}t[20000010];
int root[200010];
int n,m,sz,a,b,c;
inline int ReadInt();//输入优化
void push_down(int k, int l, int r);
int query(int k, int l, int r, int a, int b);
void modify(int &k ,int l, int r, int a, int b);
void insert();
int solve();
int main()
{
n = ReadInt();
m = ReadInt();
for(int Z = 1; Z <= m; Z ++)
{
int f = ReadInt();
a = ReadInt();
b = ReadInt();
c = ReadInt();
if(f == 1)
{
c = n - c + 1;
insert();
}
else
printf("%d\n",n - solve() + 1);
}
return 0;
}
inline int ReadInt()
{
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;
}
void push_down(int k, int l, int r)
{
if(!t[k].lazy || l == r) return;
if(!t[k].l) sz ++, t[k].l = sz;
if(!t[k].r) sz ++, t[k].r = sz;
t[ t[k].l ].lazy += t[k].lazy;
t[ t[k].r ].lazy += t[k].lazy;
int mid = (l + r) >> 1;
t[ t[k].l ].sum = (mid - l + 1) * t[k].lazy;
t[ t[k].r ].sum = (r - mid) * t[k].lazy;
t[k].lazy = 0;
}
int query(int k, int l, int r, int a, int b)
{
if(!k) return 0;
push_down(k,l,r);
if(l == a && r == b) return t[k].sum;
int mid = (l + r) >> 1;
if(b <= mid) return query(t[k].l, l, mid, a, b);
else if(a > mid) return query(t[k].r, mid + 1, r, a, b);
else return query(t[k].l, l, mid, a, mid) + query(t[k].r, mid + 1, r, mid + 1, b);
}
void modify(int &k ,int l, int r, int a, int b)
{
if(!k) sz ++, k = sz;
push_down(k,l,r);
if(l == a && r == b)
{
t[k].sum += r - l + 1;
t[k].lazy ++;
return;
}
int mid = (l + r) >> 1;
if(b <= mid) modify(t[k].l, l, mid, a, b);
else if(a > mid) modify(t[k].r, mid + 1, r, a, b);
else
{
modify(t[k].l, l, mid, a, mid);
modify(t[k].r, mid + 1, r, mid + 1, b);
}
t[k].sum = t[ t[k].l ].sum + t[ t[k].r ].sum;
}
void insert()
{
int k = 1, l = 1, r = n;
while(l != r)
{
int mid = (l + r) >> 1;
modify(root[k], 1, n, a, b);
if(c <= mid) r = mid, k = k << 1;
else l = mid + 1, k = k << 1|1;
}
modify(root[k], 1, n, a, b);
}
int solve()
{
int k = 1, l = 1, r = n;
while(l != r)
{
int mid = (l + r) >> 1;
int t = query(root[k << 1], 1, n, a, b);
if(t >= c) r = mid, k <<= 1;
else l = mid + 1, k = k << 1|1, c -= t;
}
return l;
}