暑假训练(UVALive 5789-5799)(线段树+并查集+dp+桥)

来源:互联网 发布:万维软件豪华版 编辑:程序博客网 时间:2024/05/22 12:57

A :http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83308#problem/A
题意:将区间(l,r)的人杀掉,并且输出左边和右边第一个没死的人
思路:线段树,或者并查集

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;typedef long long LL;const int maxn=100010;const int maxm=1010;const int MOD=1e9+7;const int INF=0x3f3f3f3f;int N,M;struct IntervalTree{    int setv[maxn<<2];    int sum[maxn<<2];    void build(int o,int l,int r){        setv[o]=0;        if(l==r){            sum[o]=1;            return ;        }        int mid=(l+r)>>1;        build(o<<1,l,mid);        build(o<<1|1,mid+1,r);        pushup(o);    }    void pushup(int o){        sum[o]=sum[o<<1]+sum[o<<1|1];    }    void update(int o,int l,int r,int q1,int q2){        if(q1<=l&&r<=q2){            setv[o]=1;            sum[o]=0;            return ;        }        pushdown(o);        int mid=(l+r)>>1;        if(q1<=mid)update(o<<1,l,mid,q1,q2);        if(q2>mid)update(o<<1|1,mid+1,r,q1,q2);        pushup(o);    }    void pushdown(int o){        if(setv[o]){            setv[o<<1]=setv[o<<1|1]=setv[o];            sum[o<<1]=sum[o<<1|1]=0;            setv[o]=0;        }    }    int getsum(int o,int l,int r,int q1,int  q2){        if(q1<=l&&r<=q2){            return sum[o];        }        pushdown(o);        int mid=(l+r)>>1;        int ans=0;        if(q1<=mid)ans+=getsum(o<<1,l,mid,q1,q2);        if(q2>mid)ans+=getsum(o<<1|1,mid+1,r,q1,q2);        return ans;    }    int getL(int o,int l,int r,int x){        if(l==r){            return l;        }        int mid=(l+r)>>1;        if(sum[o<<1]>=x){            return getL(o<<1,l,mid,x);        }        return getL(o<<1|1,mid+1,r,x-sum[o<<1]);    }    int getR(int o,int l,int r,int x){        if(l==r)return l;        int mid=(l+r)>>1;        if(sum[o<<1|1]>=x){            return getR(o<<1|1,mid+1,r,x);        }        return getR(o<<1,l,mid,x-sum[o<<1|1]);    }}tree;int main(){    int l,r;    while(scanf("%d%d",&N,&M)!=EOF,N+M){        tree.build(1,1,N);        int ans1,ans2,sum1,sum2,sum3;        while(M--){            scanf("%d%d",&l,&r);            tree.update(1,1,N,l,r);            if(l==1){                ans1=-1;            } else {                sum1=tree.getsum(1,1,N,1,l-1);                if(sum1<=0)ans1=-1;                else ans1=tree.getL(1,1,N,sum1);            }            if(r==N){                ans2=-1;            } else {                sum2=tree.getsum(1,1,N,r+1,N);                if(sum2<=0)ans2=-1;                else ans2=tree.getR(1,1,N,sum2);            }            if(ans1==-1)printf("* ");            else printf("%d ",ans1);            if(ans2==-1)printf("*\n");            else printf("%d\n",ans2);        }        printf("-\n");    }    return 0;}

H: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83308#problem/H
题意:给出一个图,然后是一些查询,每次输出uv之间是否存在唯一的一条路,这条路经过的点是唯一的
思路:因为路唯一,并且点不重复,也就是两个点之间的边都是桥,那么本题的解法也就是找出所有的桥,然后根据桥建图,判断两个点是不是可达就行了,这里可达也就是在一个联通集合中,所以可以用并查集维护

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;typedef long long LL;const int maxn=10010;const int maxm=100010;const int MOD=1e9+7;const int INF=0x3f3f3f3f;int R,C,Q;int low[maxn],dfn[maxn],dfs_clock;struct Edge{    int from,to,id;    Edge(int f=0,int t=0,int _id=0):from(f),to(t),id(_id){}};vector<Edge> g[maxn],G[maxn];int pre[maxn];int find(int x){    if(x==pre[x])return x;    return pre[x]=find(pre[x]);}int tarjan(int u,int fa){    int lowu=dfn[u]=++dfs_clock;    int child=0;    int len=g[u].size();    for(int i=0;i<len;i++){        Edge e=g[u][i];        int v=e.to;        if(!dfn[v]){            child++;            int lowv=tarjan(v,u);            lowu=min(lowv,lowu);            if(lowv>dfn[u]){                 pre[find(e.from)]=e.to;             }        }        else if(dfn[v]<dfn[u]&&v!=fa)            lowu=min(lowu,dfn[v]);    }    low[u]=lowu;    return lowu;}bool vis[maxn];bool dfs(int u,int d,int fa){    if(vis[u])return false;    if(u==d)return true;    vis[u]=1;    int len=G[u].size();    for(int i=0;i<len;i++){        int v=G[u][i].to;        if(v==fa)continue;        if(dfs(v,d,u))return true;    }    return false;}int main(){    int u,v;    while(scanf("%d%d%d",&R,&C,&Q)!=EOF,R+C+Q){        for(int i=0;i<=R;i++){            g[i].clear();            G[i].clear();            pre[i]=i;            dfn[i]=0;        }        dfs_clock=0;        for(int i=1;i<=C;i++){            scanf("%d%d",&u,&v);            g[u].push_back(Edge(u,v,i));            g[v].push_back(Edge(v,u,i));        }        for(int i=1;i<=R;i++){            if(!dfn[i])tarjan(i,-1);        }        while(Q--){            scanf("%d%d",&u,&v);            if(find(u)==find(v)){                printf("Y\n");            } else {                printf("N\n");            }        }        printf("-\n");    }    return 0;}

J:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=83308#problem/J

题意:给出一个hash函数,有两种操作,将位置i上的数变成x,输出区间的hash值
思路:树状数组维护一个所有数的hash,也就是Bifj,那么区间查询的时候,直接减去之后,除以一个多出来的B的次方就可以了

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;typedef long long LL;const int MAXN=100010;const int INF=0x3f3f3f3f;const LL MOD=3221225473LL;int B,P,L,N;LL p[MAXN],c[MAXN];int s[MAXN];int lowbit(int x){    return x&(-x);}LL sum(int x){    LL ret=0;    while(x>0){        ret=(ret+c[x])%P;        x-=lowbit(x);    }    return ret;}void add(int x,LL v){    while(x<=L){        c[x]=(c[x]+v)%P;        x+=lowbit(x);    }}LL bigpow(LL x,LL n,LL MOD){    LL ret=1,t=x%MOD;    while(n){        if(n&1) ret=ret*t%MOD;        t=t*t%MOD;        n>>=1;    }    return ret;}int main(){    while(scanf("%d%d%d%d",&B,&P,&L,&N)!=EOF&&(B||P||L||N)){        p[0]=1;        for(int i=1;i<=L;i++) p[i]=p[i-1]*B%P;        memset(c,0,sizeof(c));        memset(s,0,sizeof(s));        int a,b;        char str[10];        while(N--){            scanf("%s%d%d",str,&a,&b);            if(str[0]=='E'){                a=L-a+1;                add(a,((b-s[a])*p[a-1]%P+P)%P);                s[a]=b;            }            else if(str[0]=='H'){                a=L-a+1;                b=L-b+1;                LL ans=(sum(a)-sum(b-1)+P)%P*bigpow(p[b-1],P-2,P)%P;                printf("%lld\n",ans);            }        }        printf("-\n");    }    return 0;}
0 0