@zzzc18
2017-10-23T16:11:04.000000Z
字数 3038
阅读 1109
TEST
好久没动博客了。。。
两种做法
先按出现的位置排序然后连边的条件就可以改为
即此时,又可以发现
所以每次我们查询对于满足的所有 里的最大团大小(最大团最后加入的点应该是 )
由于可知,这个满足条件的 对应的最大团可以把 加进去,最大团大小变大
具体怎么实现,就是一个权值线段树,存团的大小
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 400000+9;
int n;
struct PAIR{
int loc,val;
}num[MAXN];
int b[MAXN];
int len;
int ans=1;
struct T{
int ls,rs,left_range,right_range;
int val;
}tree[MAXN*4];
int cnt;
int lazy[MAXN*4];
bool cmp(const PAIR &A,const PAIR &B){
return A.loc<B.loc;
}
void update(int x){
tree[x].val=max(tree[tree[x].ls].val,tree[tree[x].rs].val);
}
void pushdown(int x){
if(lazy[x]==0)return;
if(tree[x].ls){
tree[tree[x].ls].val=max(tree[tree[x].ls].val,lazy[x]);
lazy[tree[x].ls]=max(lazy[tree[x].ls],lazy[x]);
}
if(tree[x].rs){
tree[tree[x].rs].val=max(tree[tree[x].rs].val,lazy[x]);
lazy[tree[x].rs]=max(lazy[tree[x].rs],lazy[x]);
}
lazy[x]=0;
}
int Build(int l,int r){
int now=++cnt;
tree[now].left_range=l;
tree[now].right_range=r;
if(l==r){
tree[now].val=0;
return now;
}
int mid=(l+r)>>1;
tree[now].ls=Build(l,mid);
tree[now].rs=Build(mid+1,r);
update(now);
return now;
}
int getmax(int k,int l,int r){
pushdown(k);
if(l<=tree[k].left_range && tree[k].right_range<=r){
return tree[k].val;
}
int mid=tree[k].left_range + tree[k].right_range >> 1;
int re=0;
if(l<=mid)re=max(re,getmax(tree[k].ls,l,r));
if(r>=mid+1)re=max(re,getmax(tree[k].rs,l,r));
update(k);
return re;
}
void modify(int k,int pos,int val){
pushdown(k);
if(tree[k].left_range==tree[k].right_range){
tree[k].val=val;
lazy[k]=val;
return;
}
int mid=tree[k].left_range + tree[k].right_range >> 1;
if(pos<=mid)modify(tree[k].ls,pos,val);
else modify(tree[k].rs,pos,val);
update(k);
}
void solve(){
Build(1,len);
for(int i=1;i<=n;i++){
int pos=lower_bound(b+1,b+len+1,num[i].loc-num[i].val)-b;
int tmp=getmax(1,1,pos);
ans=max(ans,tmp+1);
pos=lower_bound(b+1,b+len+1,num[i].loc+num[i].val)-b;
modify(1,pos,tmp+1);
}
printf("%d\n",ans);
}
int main(){
freopen("clique.in","r",stdin);
freopen("clique.out","w",stdout);
scanf("%d",&n);
int i;
for(i=1;i<=n;i++){
scanf("%d%d",&num[i].loc,&num[i].val);
}
sort(num+1,num+n+1,cmp);
int tmp=0;
for(i=1;i<=n;i++){
b[++tmp]=num[i].loc-num[i].val;
b[++tmp]=num[i].loc+num[i].val;
}
sort(b+1,b+tmp+1);
len=unique(b+1,b+tmp+1)-(b+1);
solve();
return 0;
}
好了,以上方法说明我弱智
将点看成区间(因为 )
那么两个点有连边当且仅当两个区间没有公共点。
贪心地选取更多的区间,看一下代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n,x[200100],w[200100],ans,to;
struct MU{
int l,r;
}a[200100];
bool cmp(MU u,MU v){
if(u.r==v.r)
return u.l<v.l;
return u.r<v.r;
}
int main(){
freopen("clique.in","r",stdin);
freopen("clique.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d%d",&x[i],&w[i]);
a[i].l=x[i]-w[i];a[i].r=x[i]+w[i];
}
sort(a+1,a+n+1,cmp);
ans=1;to=a[1].r;
for(int i=2;i<=n;i++){
if(a[i].l>=to){
ans++;to=a[i].r;
}
}
printf("%d\n",ans);
fclose(stdin);fclose(stdout);return 0;
}
其实,因为
可以直接用线段树进行暴力修改,维护区间最值与区间和,区间取模时,线段树内操作时,如果当区间的最大值为 、 或 小于取模的值时,可以直接
考试的时候觉得这太坑没写,直接交了个40pts暴力
坑