20191001考试总结

第一题:clique

题目描述:数轴上有n个点,第i个点的坐标为 xi,权值为 wi。两个点间存在一条边当且仅当abs(xi-xj)>=wi+wj求最大团点数。(n<=200000,xi,wi<=10^9)

题解:把点按x排序,f[i]表示前i个点(必须包含i)的最大团点数f[i]=max(f[j])+1(xi-xj>=wi+wj => xi-wi>=xj+wj)把xi+wi离散化后线段树优化(这里用了zkw线段树常数比较小)

分析:这道题想出来只用了几分钟,写得也比较快,作为第一题并没有耽误什么时间(๑Ő௰Ő๑)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200000+10;
inline void getint(int&num){
    char c;int flag=1;num=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
    num*=flag;
}
int n,siz,tep,M;
long long Max[N<<3];
int x[N],w[N],tmp[N],id[N],f[N];
void insert(int pos,int val){
    long long a;
    val-=f[pos];
    Max[pos+M]+=val;
    for(pos=pos+M;pos;pos>>=1){
        a=max(Max[pos<<1],Max[pos<<1|1]);
        Max[pos<<1]-=a,Max[pos<<1|1]-=a,Max[pos]+=a;
    }
}
long long getmax(int s,int t){
    if(t<s) return 0;
    long long L=0,R=0,res=0;
    if(s==t){
        s+=M;
        while(s)  res+=Max[s],s>>=1;
        return res;
    }
    for(s=s+M,t=t+M;s^t^1;s>>=1,t>>=1){
        L+=Max[s],R+=Max[t];
        if(~s&1)    L=max(L,Max[s^1]);
        if(t&1) R=max(R,Max[t^1]);
    }
    res=max(L+Max[s],R+Max[t]);
    while(s)    res+=Max[s>>=1];
    return res;
}
bool cmp(int a,int b){
    return x[a]<x[b];
}
void build(int n){
    for(M=1;M<n;M<<=1);M--;
}
int main(){
    freopen("clique.in","r",stdin);
    freopen("clique.out","w",stdout);
    getint(n);
    for(int i=1;i<=n;i++){
        getint(x[i]),getint(w[i]);
        tmp[i]=x[i]+w[i],id[i]=i;
    }
    sort(id+1,id+n+1,cmp);
    sort(tmp+1,tmp+n+1);
    int siz=unique(tmp+1,tmp+n+1)-tmp-1;
    build(siz);
    for(int i=1;i<=n;i++){
        int t=id[i];
        int p=upper_bound(tmp+1,tmp+siz+1,x[t]-w[t])-tmp-1;
        tep=getmax(1,p);
        p=lower_bound(tmp+1,tmp+siz+1,x[t]+w[t])-tmp;
        if(f[p]>tep+1) continue ;
        insert(p,tep+1);
        f[p]=tep+1;
    }
    cout<<getmax(1,siz)<<endl;
}

第二题:mod

题目描述:给定一个长度为n的非负整数序列a,需要支持如下操作:
1:给定l,r,输出a[l]+a[l+1]+…+a[r]。
2:给定l,r,x,将a[l],a[l+1],…+a[r]对x取模。
3:给定k,y,将a[k]修改为y。

题解:线段树暴力,维护区间最大值,当max[l,r] < mod时结束操作,因为一个数最多被取模mod次,时间为O(nlognlogn)

分析:前一天打了分块的板,再加上第一题写了线段树,然后一直想分块,怎么算时间复杂度都过不了°(°ˊДˋ°) °,考完瞬间发现线段树没有什么不对 (๑>m<๑) ,完全莫名智障了一下。。。(还忘了开long long)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int L=320+5;
const int N=100000+10;
inline void getint(int&num){
    char c;num=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
}
inline void getint(long long&num){
    char c;num=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
}
struct node{
    int l,r,Max;
    long long sum;
}tree[N<<2];
int n,T,op,l,r,mod,tep;
void update(int x){
    tree[x].sum=tree[lson].sum+tree[rson].sum;
    tree[x].Max=max(tree[lson].Max,tree[rson].Max);
}
void build(int x,int l,int r){
    tree[x].l=l,tree[x].r=r;
    if(l==r){
        getint(tree[x].sum);
        tree[x].Max=tree[x].sum;
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    update(x);
}
void insert(int x,int pos,int val){
    if(tree[x].l==pos&&tree[x].r==pos)
        tree[x].Max=tree[x].sum=val;
    else{
        int mid=(tree[x].l+tree[x].r)>>1;
        if(pos<=mid) insert(lson,pos,val);
        else insert(rson,pos,val);
        update(x);
    }
}
void getmax(int x,int l,int r){
    if(tree[x].l>r||tree[x].r<l) return ;
    else if(tree[x].l>=l&&tree[x].r<=r)
        tep=max(tep,tree[x].Max);
    else getmax(lson,l,r),getmax(rson,l,r);
}
long long getsum(int x,int l,int r){
    if(tree[x].l>r||tree[x].r<l) return 0;
    else if(tree[x].l>=l&&tree[x].r<=r)
        return tree[x].sum;
    return getsum(lson,l,r)+getsum(rson,l,r);
}
void Mod(int x,int l,int r,int mod){
    if(tree[x].Max<mod) return ;
    else if(tree[x].l==tree[x].r)
        tree[x].Max=(tree[x].sum%=mod);
    else{
        int mid=(tree[x].l+tree[x].r)>>1;
        if(l<=mid) Mod(lson,l,r,mod);
        if(r>mid) Mod(rson,l,r,mod);
        update(x);
    }
}
int main(){
    freopen("mod.in","r",stdin);
    freopen("mod.out","w",stdout);
    getint(n),getint(T);
    build(1,1,n);
    while(T--){
        getint(op);
        if(op==1){
            getint(l),getint(r);
            cout<<getsum(1,l,r)<<endl;
        }
        else if(op==2){
            getint(l),getint(r),getint(mod);
            Mod(1,l,r,mod);
        }
        else{
            getint(l),getint(mod);
            insert(1,l,mod);
        }
    }
}
/*
5 5
1 2 3 4 5
2 3 5 4
3 3 5
1 2 5
2 1 3 3
1 1 3
*/

总结:完全是做完第一题之后就没有干任何有意义的事情了(๑•́ ₃ •̀๑)第二题真的很遗憾。。。也很尴尬,一直卡在那里/(ㄒoㄒ)/~~还是对mod和线段树不太熟悉了。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值