CodeForces 589G 线段树
2016-02-18 21:40
351 查看
题意:给一个数组,要求1到k的连续区间中大于d的元素与d之差值,的和大于等于r,求k的最小值,即对应的最小下标。
代码执行思路:
将不同的访问按限制d从小到大排序,则后面的元素可以继承前面的使用,节省时间。
开一个线段树,节点保存元素:sum(区间和),min(区间最小值),max(区间最大值),cap(区间有效元素数量)。
1,当d<=min时,取sum-d*cap。2,d>=max时,删除该区间。中间多搞几次二分,并且注意对于sum的运算要用long long,即可ac,具体实现看代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=2e5+300;
const int INF=0x3f3f3f3f;
int N,M,T,D,R,ans[maxn];
struct node
{
int l,r,minn,maxx,del,cap;
long long sum;
}p[maxn<<2];
struct person
{
int d,r,id;
bool operator <(const person &b)const
{
return d<b.d;
}
}pp[maxn];
void creat_tree(int l,int r,int q)
{
p[q].l=l,p[q].r=r,p[q].sum=0;
p[q].del=0,p[q].minn=INF,p[q].maxx=-INF;
p[q].cap=(r-l+1);
if(l==r)return;
int m=(l+r)>>1;
creat_tree(l,m,q<<1);
creat_tree(m+1,r,q<<1|1);
}
void dele(int q)
{
p[q].del=1,p[q].sum=0,
p[q].minn=INF,p[q].maxx=-INF,p[q].cap=0;
return;
}
void push_down(int q)
{
if(p[q].l!=p[q].r&&p[q].del==1)
{
dele(q<<1);
dele(q<<1|1);
}
return;
}
void push_up(int q)
{
if(p[q].l!=p[q].r)
{
p[q].sum=p[q<<1].sum+p[q<<1|1].sum;
p[q].minn=min(p[q<<1].minn,p[q<<1|1].minn);
p[q].maxx=max(p[q<<1].maxx,p[q<<1|1].maxx);
p[q].cap=p[q<<1].cap+p[q<<1|1].cap;
if(p[q<<1].del==1&&p[q<<1|1].del==1)dele(q);
}
return;
}
void insert(int val,int po,int q)
{
if(p[q].l==p[q].r)
{
p[q].sum=val;
p[q].minn=val;
p[q].maxx=val;
p[q].cap=1;
return;
}
int m=(p[q].l+p[q].r)>>1;
if(po<=m)
insert(val,po,q<<1);
else
insert(val,po,q<<1|1);
push_up(q);
return;
}
long long query(int l,int r,int d,int q)
{
push_down(q);
if(l>p[q].r||r<p[q].l||p[q].del==1)return 0;
if(l<=p[q].l&&r>=p[q].r&&d>=p[q].maxx)
{
dele(q);
push_down(q);
return 0;
}
if(l<=p[q].l&&r>=p[q].r&&d<=p[q].minn)
{
return p[q].sum-(long long)d*p[q].cap;
}
long long ta= query(l,r,d,q<<1)+query(l,r,d,q<<1|1);
push_up(q);
return ta;
}
int search(int di,int ri)
{
if(query(1,M,di,1)<ri)return 0;
int l=1,r=M+1,m,an;
while(l<r)
{
m=(l+r)/2;
if(query(1,m,di,1)>=ri)
{
an=m;
r=m;
}
else l=m+1;
}
return an;
}
int main()
{
//freopen("a.txt","r",stdin);
//int hh=1e10,jj=1e10;
//cout<<hh*jj<<endl;
while(~scanf("%d%d",&N,&M))
{
creat_tree(1,M,1);
for(int i=1;i<=M;i++)
{
scanf("%d",&T);
insert(T,i,1);
}
for(int i=1;i<=N;i++)
{
scanf("%d%d",&D,&R);
pp[i].d=D,pp[i].r=R,pp[i].id=i;
}
sort(pp+1,pp+1+N);
for(int i=1;i<=N;i++)
{
ans[pp[i].id]=search(pp[i].d,pp[i].r);
}
for(int i=1;i<=N;i++)
{
printf("%d",ans[i]);
if(i<N)printf(" ");
else printf("\n");
}
}
return 0;
}
代码执行思路:
将不同的访问按限制d从小到大排序,则后面的元素可以继承前面的使用,节省时间。
开一个线段树,节点保存元素:sum(区间和),min(区间最小值),max(区间最大值),cap(区间有效元素数量)。
1,当d<=min时,取sum-d*cap。2,d>=max时,删除该区间。中间多搞几次二分,并且注意对于sum的运算要用long long,即可ac,具体实现看代码。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=2e5+300;
const int INF=0x3f3f3f3f;
int N,M,T,D,R,ans[maxn];
struct node
{
int l,r,minn,maxx,del,cap;
long long sum;
}p[maxn<<2];
struct person
{
int d,r,id;
bool operator <(const person &b)const
{
return d<b.d;
}
}pp[maxn];
void creat_tree(int l,int r,int q)
{
p[q].l=l,p[q].r=r,p[q].sum=0;
p[q].del=0,p[q].minn=INF,p[q].maxx=-INF;
p[q].cap=(r-l+1);
if(l==r)return;
int m=(l+r)>>1;
creat_tree(l,m,q<<1);
creat_tree(m+1,r,q<<1|1);
}
void dele(int q)
{
p[q].del=1,p[q].sum=0,
p[q].minn=INF,p[q].maxx=-INF,p[q].cap=0;
return;
}
void push_down(int q)
{
if(p[q].l!=p[q].r&&p[q].del==1)
{
dele(q<<1);
dele(q<<1|1);
}
return;
}
void push_up(int q)
{
if(p[q].l!=p[q].r)
{
p[q].sum=p[q<<1].sum+p[q<<1|1].sum;
p[q].minn=min(p[q<<1].minn,p[q<<1|1].minn);
p[q].maxx=max(p[q<<1].maxx,p[q<<1|1].maxx);
p[q].cap=p[q<<1].cap+p[q<<1|1].cap;
if(p[q<<1].del==1&&p[q<<1|1].del==1)dele(q);
}
return;
}
void insert(int val,int po,int q)
{
if(p[q].l==p[q].r)
{
p[q].sum=val;
p[q].minn=val;
p[q].maxx=val;
p[q].cap=1;
return;
}
int m=(p[q].l+p[q].r)>>1;
if(po<=m)
insert(val,po,q<<1);
else
insert(val,po,q<<1|1);
push_up(q);
return;
}
long long query(int l,int r,int d,int q)
{
push_down(q);
if(l>p[q].r||r<p[q].l||p[q].del==1)return 0;
if(l<=p[q].l&&r>=p[q].r&&d>=p[q].maxx)
{
dele(q);
push_down(q);
return 0;
}
if(l<=p[q].l&&r>=p[q].r&&d<=p[q].minn)
{
return p[q].sum-(long long)d*p[q].cap;
}
long long ta= query(l,r,d,q<<1)+query(l,r,d,q<<1|1);
push_up(q);
return ta;
}
int search(int di,int ri)
{
if(query(1,M,di,1)<ri)return 0;
int l=1,r=M+1,m,an;
while(l<r)
{
m=(l+r)/2;
if(query(1,m,di,1)>=ri)
{
an=m;
r=m;
}
else l=m+1;
}
return an;
}
int main()
{
//freopen("a.txt","r",stdin);
//int hh=1e10,jj=1e10;
//cout<<hh*jj<<endl;
while(~scanf("%d%d",&N,&M))
{
creat_tree(1,M,1);
for(int i=1;i<=M;i++)
{
scanf("%d",&T);
insert(T,i,1);
}
for(int i=1;i<=N;i++)
{
scanf("%d%d",&D,&R);
pp[i].d=D,pp[i].r=R,pp[i].id=i;
}
sort(pp+1,pp+1+N);
for(int i=1;i<=N;i++)
{
ans[pp[i].id]=search(pp[i].d,pp[i].r);
}
for(int i=1;i<=N;i++)
{
printf("%d",ans[i]);
if(i<N)printf(" ");
else printf("\n");
}
}
return 0;
}
相关文章推荐
- 1013. Battle Over Cities (25)
- 单调递增最长子序列(动态规划)
- C++ in the modern world(为什么C++不会衰老)
- POJ 2549 Sumsets(折半枚举)
- C++ in the modern world(为什么C++不会衰老)
- Vivado增量式编译
- 编程逻辑:按图索骥
- iOS 【iOS ViewController的跳转形式 Present ViewController Modally】
- 简单的java Socket 例子
- 求解最大矩形面积 — leetcode 85. Maximal Rectangle
- 身份证识别,银行卡识别,名片识别
- ANDROID内存优化
- Ant + android sdk 生成并发布APK
- 【模板】线段树
- 多态经典面试题
- cc.Class.extend 不写ctor函数的后果
- 第四章 类加载机制
- Windows 10系统更换Windows 7系统磁盘分区注意事项二
- 算法竞赛入门经典 蛇形填数
- SVN图标不显示的2种处理方式