2017 Multi-University Training Contest

来源:互联网 发布:期刊软件 编辑:程序博客网 时间:2024/06/05 18:54

1003(hdu6035Colorful Tree)题目:http://acm.hdu.edu.cn/showproblem.php?pid=6035.

题意:树上每个点有自己的颜色,树上每条路径的贡献值是这条路径上的点的不同颜色个数,求所有路径的贡献总和

求所有路径上不同颜色的个数和,其实也就是求所有颜色被多少条路径经过,这个并不好求,可以转化为求所有颜色不被哪些路径经过,最后用总路径条数减一下就可以了

求的方法很巧妙,考虑一颗根的颜色为c1,节点号为n1的子树,这颗子树上的节点和别的节点都不可能有不经过根n1的路径,在把这颗子树上所有根的颜色为c1的子树去掉,剩下的节点任意两两之间(不包括根节点n1)都会有一条不经过c1的路径,按照这个思想去求,可以dfs前缀实现,也可以全部处理,遍历实现

标程是先处理,后遍历,主要是二分那块比较难懂,其实就是去掉子树上所有根的颜色为c1的子树。

#include<bits/stdc++.h>using namespace std;const int maxn=200005;long long fun(long long x){    return x*(x-1)>>1;}vector<int>w[maxn],c[maxn];int num[maxn],n,l[maxn],r[maxn],fa[maxn],cnt=0;long long ans;int dfs(int x,int f){    num[x]=1,fa[x]=f;    l[x]=++cnt;    for(int i=0;i<w[x].size();i++)    {        int now=w[x][i];        if(now==f)            continue;        dfs(now,x);        num[x]+=num[now];    }    r[x]=cnt;}int cmp(int u,int v){    return l[u]<l[v];}int main(){    int tcase=0,i,j,ii,u,v;    while(cin>>n)    {        ans=cnt=0;        tcase++;        memset(num,0,sizeof(num));        for(i=1;i<=n;i++)            scanf("%d",&u),c[u].push_back(i);        for(i=1;i<n;i++)        {            scanf("%d %d",&u,&v);            w[u].push_back(v);            w[v].push_back(u);        }        ans=n*fun(n);        w[0].push_back(1);        dfs(0,0);        for(i=1;i<=n;i++)        {            if(c[i].size()==0)            {                ans-=fun(n);                continue;            }            c[i].push_back(0);            sort(c[i].begin(),c[i].end(),cmp);            for(j=0;j<c[i].size();j++)            {                int x=c[i][j];                for(ii=0;ii<w[x].size();ii++)                {                    int y=w[x][ii];                    if(y==fa[x])                        continue;                    l[n+1]=l[y];                    int now=num[y];                    while(1)                    {                        vector<int>::iterator it=lower_bound(c[i].begin(),c[i].end(),n+1,cmp);                        if(it==c[i].end()||l[*it]>r[y])                            break;                        l[n+1]=r[*it]+1;                        now-=num[*it];                    }                    ans-=fun(now);                }            }        }        for(i=0;i<=n;i++)            w[i].clear(),c[i].clear();        printf("Case #%d: %lld\n",tcase,ans);    }}
看了别人前缀的方式求的很巧妙
#include<bits/stdc++.h>using namespace std;const int maxn=200005;long long fun(long long x){    return x*(x-1)>>1;}vector<int>w[maxn];int num[maxn],n,c[maxn],sum[maxn];long long ans;int dfs(int x,int fa){    num[x]=1;    int pre=sum[c[x]],sum_now=0;    for(int i=0;i<w[x].size();i++)    {        int now=w[x][i];        if(now==fa)            continue;        dfs(now,x);        int temp=sum[c[x]]-pre;        pre=sum[c[x]];        ans-=fun(num[now]-temp);        num[x]+=num[now];        sum_now+=temp;    }    sum[c[x]]+=num[x]-sum_now;}int main(){    int tcase=0,i,u,v;    while(cin>>n)    {        ans=0;        tcase++;        memset(num,0,sizeof(num));        memset(sum,0,sizeof(sum));        for(i=1;i<=n;i++)            scanf("%d",&c[i]);        for(i=1;i<n;i++)        {            scanf("%d %d",&u,&v);            w[u].push_back(v);            w[v].push_back(u);        }        ans=n*fun(n);        dfs(1,0);        for(i=1;i<=n;i++)        {            ans-=fun(n-sum[i]);        }        for(i=0;i<=n;i++)            w[i].clear();        printf("Case #%d: %lld\n",tcase,ans);    }}

1008(hdu6040  Hints of sd0061)题目:http://acm.hdu.edu.cn/showproblem.php?pid=6040

题意:根据已知函数构造序列,个数很大,给m个查询,查询这段序列里第k小的元素

直接做肯定会t,用了一个库函数nth_element()

STL中的nth_element()方法的使用 通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比这个元素小的元素都排在这个元素之前,比这个元素大的元素都排在这个元素之后,但不能保证他们是有序的。参考自

但直接用库函数也是会t的,有一种快排的思想,先找查询里k较大的,这样前k小个元素就可以都放在序列左边了,下次只需从这一部分找更小的即可。

#include<bits/stdc++.h>using namespace std;unsigned x,y,z,a[10000050],ans[200];;unsigned rng61() {  unsigned t;  x ^= x << 16;  x ^= x >> 5;  x ^= x << 1;  t = x;  x = y;  y = z;  z = t ^ x ^ y;  return z;}struct node{    int index,b;}num[200];int cmp(node u,node v){    return u.b>v.b;}int main(){    int tcase=1,n,m,i;    while(cin>>n>>m>>x>>y>>z)    {        for(i=0;i<n;i++)        a[i]=rng61();        num[0].b=n-1;        for(i=1;i<=m;i++)        scanf("%d",&num[i].b),num[i].index=i;        sort(num+1,num+m+1,cmp);        for(i=1;i<=m;i++)        {            if(num[i].b==num[i-1].b&&i!=1)                ans[num[i].index]=ans[num[i-1].index];            else            {                nth_element(a,a+num[i].b,a+num[i-1].b+1);                ans[num[i].index]=a[num[i].b];            }        }        printf("Case #%d:",tcase++);        for(i=1;i<=m;i++)        {            cout<<" "<<ans[i];        }        cout<<endl;    }    return 0;}



原创粉丝点击