51nod 1672 区间交
将右端点放进线段树,然后枚举左端点。
先对l,r排序。因为需要k个区间的相交,所以我们先将前k-1个的区间右端点放进线段树。然后在枚举k到m的时候每次将右端点放入,然后查找边界的最右边。因为l是从小到大排序,所以查找的位置一定是从后往前找第k个的数(这点不懂的可以私我),即叶子节点所以在的位置,注意这个位置一定要在当前左端点的右边!!!然后求最大值就好了。
#include<bits/stdc++.h>
#define fp(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
typedef double dl;
using namespace std;
const int N=2e5+7;
const ll M=1e9+7;
const int INF=0x3f3f3f3f;
ll n,k,m;
struct node{
int l,r;
}s[N];
struct poi{
int l,r;
int sum;
}tr[N<<2];
bool cmp(node a,node b)
{
if(a.l==b.l) return a.r<b.r;
return a.l<b.l;
}
ll a[N],pre[N];
void pushup(int u)
{
tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}
void build(int u,int l,int r)
{
tr[u]={l,r,0};
if(l==r) return ;
else
{
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
}
void modify(int u,int x)
{
if(tr[u].l==tr[u].r&&tr[u].r==x)
{
tr[u].sum++;
return ;
}
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid) modify(u<<1,x);
else if(x>mid) modify(u<<1|1,x);
pushup(u);
}
int query(int u,int k)
{
if(tr[u].l==tr[u].r) return tr[u].l;
if(tr[u<<1|1].sum>=k) return query(u<<1|1,k);
else return query(u<<1,k-tr[u<<1|1].sum);
}
void solve()
{
pre[0]=0;
scanf("%lld%lld%lld",&n,&k,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pre[i]=pre[i-1]+a[i];
for(int i=1;i<=m;i++) scanf("%d%d",&s[i].l,&s[i].r);
sort(s+1,s+m+1,cmp);
build(1,1,n);
for(int i=1;i<k;i++) modify(1,s[i].r);
ll ans=0;
for(int i=k;i<=m;i++)
{
modify(1,s[i].r);
int pos=query(1,k);
//printf("pos:%d\n",pos);
if(pos>=s[i].l)
{
ans=max(ans,pre[pos]-pre[s[i].l-1]);
//printf("pos:%d\n",pos);
}
}
printf("%lld",ans);
}
int main()
{
//ios::sync_with_stdio(0);
//cin.tie(0),cout.tie(0);
//int T; scanf("%d",&T)
//for(int i=1;i<=T;i++)
solve();
}
