2018.10.21 练习赛 树专练

T1 树

题解:

记录树上前缀和,每次加入新前缀和就二分一下前缀和数组看有无满足\(sum[now]-s\)的数在里面,因为\(sum\)必定是单调的,就乱搞完毕;

\(code\):

#include<cstdio>
#include<algorithm>
#include<ctype.h> 
#include<vector>
#include<queue>
#include<cstring>
#include<map>
#include<stdlib.h>
#include<ctime>
#define lowbit(x) (x&-x)
#define ll long long
#define ld double
#define mod 998244353 
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=x*10+tt-'0';
    if(flag) x=-x;
}

const int maxn=1e5+2;
int n,s;
vector<int>G[maxn];
bool root[maxn];
int w[maxn],sum[maxn],ans;

void dfs(int x,int dep)
{
    sum[dep]=sum[dep-1]+w[x];
    if(sum[lower_bound(
    sum,sum+dep+1,sum[dep]-s)-sum]==sum[dep]-s) ans++;
    for(int i=G[x].size()-1;i>=0;i--)
    {
        int p=G[x][i];
        dfs(p,dep+1);
    }
    sum[dep]=0;
}

int main()
{
    read(n),read(s);
    for(int i=1;i<=n;i++) read(w[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        read(x),read(y);
        G[x].push_back(y);
        root[y]=1;
    }
    for(int i=1;i<=n;i++)
    if(!root[i]) {dfs(i,1);break;}
    printf("%d",ans);
    return 0;
}

T2 联通块计数

题解:

树DP=_=

\(code:\)

#include<cstdio>
#include<algorithm>
#include<ctype.h> 
#include<vector>
#include<queue>
#include<cstring>
#include<map>
#include<stdlib.h>
#include<ctime>
#define lowbit(x) (x&-x)
#define ll long long
#define ld double
#define mod 998244353 
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=x*10+tt-'0';
    if(flag) x=-x;
}
inline ll add(ll a,ll b){return a+b<mod?a+b:a+b-mod;}
inline ll mul(ll a,ll b){return a*b<mod?a*b:a*b%mod;}
inline ll sub(ll a,ll b){return a-b<0?a-b+mod:a-b;}

const int maxn=2002;
struct node{
    ll x,id;
    inline node(ll a=0,ll b=0)
    {x=a,id=b;}
    inline bool operator<(node a)const
    {return x==a.x?a.id<a.id:x<a.x;}
}a[maxn];

ll n,k,ans,w[maxn];
vector<ll>G[maxn];
bool book[maxn];

ll dfs(ll x,ll pre,ll lim)
{
    int ret=1;
    for(int i=G[x].size()-1;i>=0;i--)
    {
        int p=G[x][i];
        if(p==pre||book[p]||w[p]>lim) continue;
        ret=mul(ret,dfs(p,x,lim));
    }
//  printf("%d\n",lim);
    return ret+=(pre!=0);
}

int main()
{
    read(n),read(k);
    for(int i=1;i<=n;i++)
    {
        ll x;
        read(x);w[i]=x;
        a[i]=node(x,i);
    }sort(a+1,a+1+n);
    for(int i=1;i<n;i++)
    {
        ll x,y;
        read(x),read(y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    for(int i=1;i<=n;i++)
    {
        if(book[a[i].id]) continue;
        book[a[i].id]=1;
        ans=add(ans,dfs(a[i].id,0,a[i].x+k));
//      printf("%d\n",ans);
    }
    printf("%lld",ans);
    return 0;
}

T2 电压

题解:

题意为去掉一条边,看此图是否仍为一个二分图;

我们考虑去掉的这条边必定是所有奇环的交,且不能在任何的偶环上,\(tarjan\)找出所有环(这里的所有环是指写出的算法所能找出的环,并非真正意义上的所有环)

每当我们遇到一条返祖边,差分记录环覆盖的边,统计答案时满足前面我们所给的条件即可;

\(code:\)

#include<cstdio>
#include<algorithm>
#include<ctype.h> 
#include<vector>
#include<queue>
#include<cstring>
#include<map>
#include<stdlib.h>
#include<ctime>
#define lowbit(x) (x&-x)
#define ll long long
#define ld double
#define mod 998244353 
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=x*10+tt-'0';
    if(flag) x=-x;
}

struct node{
    int x,id;
    inline node(int a=0,int b=0)
    {x=a,id=b;}
};

const int maxn=1e5+2;
int n,m,dep[maxn],tot;
int cnt[maxn][2];
//0 1 odd
//0 0 eve
vector<node>G[maxn];
void dfs(int x,int pre)
{
    for(int i=G[x].size()-1;i>=0;i--)
    {
        int p=G[x][i].x,id=G[x][i].id;
        if(id==pre) continue;
        if(!dep[p])
        {
            dep[p]=dep[x]+1;dfs(p,id);
            cnt[x][0]+=cnt[p][0];
            cnt[x][1]+=cnt[p][1];
        }
        else if(dep[p]<=dep[x])
        {
            if((dep[x]-dep[p])&1) cnt[x][0]++,cnt[p][0]--;
            else cnt[x][1]++,cnt[p][1]--,tot++;
        }
    }
}

int main()
{
//  freopen("voltage.in","r",stdin);
    read(n),read(m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        read(x),read(y);
        G[x].push_back(node(y,i));
        G[y].push_back(node(x,i));
    }
    int ans=0;
    for(int i=1;i<=n;i++) if(!dep[i]) dep[i]=1,dfs(i,0);
    for(int i=1;i<=n;i++) if(dep[i]!=1&&!cnt[i][0]&&cnt[i][1]==tot) ans++;
    printf("%d",ans+(tot==1));
}

猜你喜欢

转载自www.cnblogs.com/KatouKatou/p/9827577.html