2015长春网络赛题解

A.http://acm.hdu.edu.cn/showproblem.php?pid=5437

思路:维护一个优先队列,模拟开门,枚举每一个人,同时记录当先开门的位置,如果人数等于开门位置,就从队列中取出min(size(),q),放到我们的答案队列中。注意开门时间可能相同,所以要先排序,再加一个循环。还有最后一次开门,剩下的人都放进来。注意他说的只有两次ni会超过10000,所以我们可以在输入时记下查询的最大位置。当答案队列中的人大于查询的最大位置就可以退出循环了,这样就不会超时了。因为代码找不到了,就不贴了。

B.http://acm.hdu.edu.cn/showproblem.php?pid=5438

思路:在输边的时候记录每个点的度数。然后一遍循环,bfs模拟删点。最后再tarjan求联通分量。这个地方可以考虑直接bfs求联通分量的点数应该更简单。

#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN=11000;
const int MAXM=110000;
struct Edge{
    int v,nex;
}edge[MAXM];

vector<int> G[MAXN];
ll value[MAXN];
int dfn[MAXN];
int low[MAXN];
int deg[MAXN];
int head[MAXN];
int stack[MAXN];
bool instack[MAXN];
int inde,top,block;
vector<int> bblock[MAXN];
int T,p,m,u,v,tot;


void addedge(int u,int v)
{
    edge[tot].v=v;
    edge[tot].nex=head[u];
    head[u]=tot++;
}

void bfs(int u)
{
    int tmp;
    queue<int> que;
    que.push(u);
    while(!que.empty())
    {
        tmp=que.front();
        que.pop();
        for(int i=0;i<G[tmp].size();i++)
        {
            v=G[tmp][i];
            G[tmp][i]=0;
            deg[u]--,deg[v]--;
            if(deg[v]==1)
                que.push(v);
        }
    }
}

void tarjan(int u)
{
    int v;
    low[u]=dfn[u]=++inde;
    stack[top++]=u;
    instack[u]=true;
    for(int i=head[u];i!=-1;i=edge[i].nex)
    {
        v=edge[i].v;
        if(!dfn[v])
        {
            tarjan(v);
            if(low[u]>low[v])
                low[u]=low[v];
        }
        else if(instack[v]&&low[u]>dfn[v])
            low[u]=dfn[v];
    }
    if(low[u]==dfn[u])
    {
        block++;
        do{
            v=stack[--top];
            instack[v]=false;
            bblock[block].push_back(v);
        }
        while(v!=u);
    }
}

void init()
{
    for(int i=0;i<MAXN;i++)
    {
        bblock[i].clear();
        G[i].clear();
    }
    memset(value,0,sizeof(value));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(deg,0,sizeof(deg));
    memset(head,-1,sizeof(head));
    memset(instack,0,sizeof(instack));
    block=top=inde=tot=0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&p,&m);
        for(int i=1;i<=p;i++)
            scanf("%I64d",&value[i]);
        while(m--)
        {
            scanf("%d%d",&u,&v);
            if(v==u)
                continue;
            G[u].push_back(v);
            G[v].push_back(u);
            deg[u]++,deg[v]++;
        }
        for(int i=1;i<=p;i++)
            if(deg[i]==1)
                bfs(i);
        for(int i=1;i<=p;i++)
            for(int j=0;j<G[i].size();j++)
                if(G[i][j])
                    addedge(i,G[i][j]);
        for(int i=1;i<=p;i++)
            if(!dfn[i])
                tarjan(i);
        ll ans=0;
        for(int i=0;i<=block;i++)
            if(bblock[i].size()>1&&bblock[i].size()%2)
                for(int j=0;j<bblock[i].size();j++)
                    ans+=value[bblock[i][j]];
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

E.http://acm.hdu.edu.cn/showproblem.php?pid=5441

思路:离线并查集。把边和询问分别排序。然后往里面加边,设边e的点u,v所在集合的节点数量为cnt[u],cnt[v].那么ans=ans-cnt[u]*(cnt[u]-1)-cnt[v]*(cnt[v]-1)+(cnt[u]+cnt[v])*(cnt[u]+cnt[v]-1), 再把u集合并入v集合,cnt[u]+=cnt[v]。

#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=25000;
const int MAXM=110000;
const int MAXQ=6000;
int par[MAXN];
int cnt[MAXN];
int ansx[MAXQ];
int n,m,q,T;
struct Edge{
    int u,v,w;
}edge[MAXM];

struct Query{
    int w,id;
}query[MAXQ];

bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

bool cmp2(Query a,Query b)
{
    return a.w<b.w;
}
int find(int x)
{
    return x==par[x]?x:par[x]=find(par[x]);
}

void init()
{
    for(int i=0;i<MAXN;i++)
        cnt[i]=1,par[i]=i;
}

int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d%d",&n,&m,&q);
        for(int i=0;i<m;i++){
            //if(u==v) continue;
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        }
        sort(edge,edge+m,cmp);
        for(int i=0;i<q;i++)
        {
            scanf("%d",&query[i].w);
            query[i].id=i;
        }
        sort(query,query+q,cmp2);
        int sh=0;
        int ans=0;
        for(int i=0;i<m;i++)
        {
            Edge e=edge[i];
            //printf("%d %d %d\n",e.w,sh+,query[sh]);
            while(sh<q&&e.w>query[sh].w)
                ansx[query[sh++].id]=ans;
            int u=find(e.u);
            int v=find(e.v);
            if(u==v)
                continue;
            ans-=cnt[u]*(cnt[u]-1);
            ans-=cnt[v]*(cnt[v]-1);
            par[v]=u;
            cnt[u]+=cnt[v];
            ans+=cnt[u]*(cnt[u]-1);
        }
        while(sh<q)
            ansx[query[sh++].id]=ans;
        for(int i=0;i<q;i++)
            printf("%d\n",ansx[i]);
    }
    return 0;
}
View Code

G.http://acm.hdu.edu.cn/showproblem.php?pid=5443

签到题,暴力也能过。

H.http://acm.hdu.edu.cn/showproblem.php?pid=5444

思路:模拟建树就好。

#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1100;
struct Node{
    int l,r;
    int id;
}node[MAXN];

void find(int pos,int to)
{
    int x=0;
    while(1)
    {
        if(node[x].id>=to)
        {
            if(!node[x].r)
            {
                node[x].r=pos;
                break;
            }
            else
                x=node[x].r;
        }
        else
        {
            if(!node[x].l)
            {
                node[x].l=pos;
                break;
            }
            else
                x=node[x].l;
        }
    }
}

void solve(int to)
{
    int x=0;
    while(1)
    {
        if(node[x].id==to)
            break;
        if(node[x].id>to)
        {
            printf("E");
            x=node[x].r;
        }
        else
        {
            printf("W");
            x=node[x].l;
        }
    }
}

int T,n,q,to;

int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        memset(node,0,sizeof(node));
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&node[i].id);
            if(i==0)
                continue;
            find(i,node[i].id);
        }
        scanf("%d",&q);
        for(int i=0;i<q;i++)
        {
            scanf("%d",&to);
            solve(to);
            puts("");
        }
    }
    return 0;
}
View Code

 

posted on 2015-09-15 20:12  onlyAzha  阅读(171)  评论(0编辑  收藏  举报

导航