1. 程式人生 > >2018CCPC女生賽(樹上莫隊)

2018CCPC女生賽(樹上莫隊)

簽到題這裡久懶得寫了。

B - 缺失的資料範圍

Total Submission(s): 2602    Accepted Submission(s): 559

題意:求最大的N,滿足N^a*[log2(N)]^b<=K;

思路:二分即可,log2要手寫,然後就是注意判pow是否超過long long。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1000100;
const ll inf=1e18;
ll A,B,K,ans,aa[
61]; ll Log(ll x){ int pos=lower_bound(aa+1,aa+60+1,x)-aa; return pos; } bool check(ll x){ ll a=1,res=1; ll b=Log(x);// cout<<b<<" "<<aa[b]<<" "; for(int i=1;i<=A;i++){ if(a>K/x) return false; a=a*x; if(a>K) return false; }
for(int i=1;i<=B;i++){ if(res>K/b) return false; res=res*b; if(res>K) return false; } //cout<<a<<" "<<b<<endl; if(a>K/res) return false; if(a*res<=K) return true; } int main() { int T; aa[0]=1; for(int i=1;i<=60
;i++) aa[i]=aa[i-1]*2; scanf("%d",&T); while(T--){ scanf("%lld%lld%lld",&A,&B,&K); ans=0; ll L=1,R=K; while(L<=R){ ll Mid=(L+R)/2; if(check(Mid)) ans=Mid,L=Mid+1; else R=Mid-1; } printf("%lld\n",ans); } return 0; }
View Code

E - 對稱數

Total Submission(s): 469    Accepted Submission(s): 88

題意:給出一棵帶點權的樹,Q次詢問,每次詢問給出(u,v),求這個路徑上最小的出現次數位偶數的正整數。

思路:樹上莫隊:皇室聯邦法分塊,括號法移動區間。

皇室聯邦法分塊:即按照DFS虛分塊。

括號法:dfs時,記錄第一次訪問時間戳in[]和最後一次訪問時間戳out[]。如果訪問路徑(u,v),保證in[u]<in[v]起對應的區間就是:

1,LCA==u,對應[in[u],in[v]];

2,LCA!=u,對應[out[u],in[v]]+LCA;LCA單獨考慮為pre,不要忽略。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=400010;
int a[maxn],Laxt[maxn],Next[maxn],To[maxn],cnt,B;
int g[maxn],dep[maxn],fa[maxn][20],ans[maxn],scc,tot;
int in[maxn],out[maxn],p[maxn];
bitset<maxn>Set;
struct in{
    int u,v,id;
    friend bool operator <(in ww,in vv){
        if(g[ww.u]==g[vv.u]) return g[ww.v]<g[vv.v];
        return g[ww.u]<g[vv.u];
    }
}s[maxn];
void add(int u,int v)
{
    Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;
}
void dfs(int u,int f)
{
    fa[u][0]=f;  dep[u]=dep[f]+1;
    if(tot%B==0) scc++;  g[u]=scc;
    in[u]=++tot;  p[tot]=a[u];
    for(int i=Laxt[u];i;i=Next[i]){
        if(To[i]!=f) dfs(To[i],u);
    }
    out[u]=++tot; p[tot]=a[u];
}
int LCA(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=18;i>=0;i--)
         if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
    if(u==v) return u;
    for(int i=18;i>=0;i--)
        if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
int main()
{
    int T,N,M,u,v,Lca;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&M); B=sqrt(N);
        cnt=0; rep(i,1,N) Laxt[i]=0;
        rep(i,1,N) scanf("%d",&a[i]);
        rep(i,1,N-1){
            scanf("%d%d",&u,&v);
            add(u,v); add(v,u);
        }
        tot=0; scc=0; dfs(1,0);
        rep(i,1,18) rep(j,1,N) fa[j][i]=fa[fa[j][i-1]][i-1];
        rep(i,1,M) scanf("%d%d",&s[i].u,&s[i].v),s[i].id=i;
        rep(i,1,M) if(in[s[i].u]>in[s[i].v]) swap(s[i].u,s[i].v);
        sort(s+1,s+M+1);
        Set.set();
        int L=1,R=1,pre=0; Set.flip(p[1]);
        rep(i,1,M) {
            Set.flip(pre);
            int Lca=LCA(s[i].u,s[i].v),l,r;
            if(Lca==s[i].u) l=in[s[i].u],r=in[s[i].v],pre=0;
            else l=out[s[i].u],r=in[s[i].v],Set.flip(a[Lca]),pre=a[Lca];
            while(l<L) Set.flip(p[--L]);
            while(l>L) Set.flip(p[L++]);
            while(r>R) Set.flip(p[++R]);
            while(r<R) Set.flip(p[R--]);
            int pos=Set._Find_next(0);
            ans[s[i].id]=pos;
        }
        rep(i,1,M) printf("%d\n",ans[i]);
    }
    return 0;
}
View Code

I - 迴文樹

題意:給出一棵帶權樹,點權隨機給出,求樹上有多少迴文串。

思路:由於是隨機,我們大膽猜測,只存在長度為1,2和3的迴文串。

Total Submission(s): 198    Accepted Submission(s): 45

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=100010;
int a[maxn]; map<int,int>mp[maxn];
int main()
{
    int N,T,u,v;
    scanf("%d",&T);
    while(T--){
        int ans=0;
        scanf("%d",&N);
        rep(i,1,N) mp[i].clear();
        rep(i,1,N) scanf("%d",&a[i]);
        rep(i,1,N-1){
            scanf("%d%d",&u,&v);
            if(a[u]==a[v]) ans++;
            ans+=mp[u][a[v]];
            ans+=mp[v][a[u]];
            mp[u][a[v]]++; mp[v][a[u]]++;
        }
        printf("%d\n",ans+N);
    }
    return 0;
}
View Code