1. 程式人生 > >2018.10.21 練習賽 樹專練

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));
}