zoukankan      html  css  js  c++  java
  • VP

    这场比赛我只打了一个小时,赛时通过 ( ext{A,B,C}),排名 (880)(算上 Unofficial)。

    A

    略。

    B

    略。

    C

    显然让每个点的数都取它的边界是最优的,然后 dp 即可。

    D

    考虑点 (1) 的配对,设其与 (x) 构成一条线段。

    (f_i)(2i) 个点自由配对的方案数。

    • (xle n):因为从 (1) 开始的线段不可能被其它线段覆盖,所以 (1sim 2n) 一定铺满了长度为 ((x-1)) 的线段。因为要恰好铺满,所以方案数为 (sigma_0(n))
    • (x>n):此时 (xsim 2n) 这些点一定会与 (1sim (2n-x+1)) 这些点对应地配对。因此还有 (2(x-n-1)) 个点可以随意配对,方案数即为 (sum_{i=1}^{n-1} f_i)

    E

    设 Soroush 的树是 (S),Keshi 的树是 (T)

    首先,最大团中的点一定都在 (S) 中从 (1) 到某个叶子节点的路径上。并且可以发现,在路径确定时,最优的方案是优先选在 (T) 中深度较浅的点。

    也就是说,我们要有一种算法,支持如下操作:

    • 加入一个点;
    • 删除一个点,且这个点被删除之前,其在 (S) 中的所有子孙都被删除了;
    • 询问目前点集中最多能取出多少个点,使得它们在 (T) 中两两无祖先关系。

    设操作三的点集是 (P),那么对于操作一,设加入了点 (u),假如 (u)(P) 中某个点的祖先,那么在 (P) 中加入 (u) 显然不优;否则将 (P)(u) 的祖先删除并加入 (u)

    如何查询 (P) 中是否有 (u) 的祖先?考虑预处理 (T) 的欧拉序,记为 ((st_u,ed_u)),并维护 (P) 中所有点的从小到大排序的 (st)。因为要查的是 (u) 的祖先(记为 (x)),所以一定有 (st_xle st_uland ed_xge ed_u)。找到 (P) 中最后一个满足 (st_xle st_u)(x),可以证明,如果 (P) 中存在 (u) 的祖先,那么它一定是 (x)

    证明

    假如 (P) 中存在某个点 (v(v eq x)) 使得 (v)(u) 的祖先,那么有 (st_v<st_x)。讨论 (x) 的两种可能:

    • 如果 (x)(u) 的祖先,那么显然得证;
    • 如果 (x) 不是 (u) 的祖先,那么有 (ed_x<ed_u)。因为 (v)(u) 的祖先,所以 (st_v<st_xland ed_v>ed_x),即 (v) 也是 (x) 的祖先,与 (P) 的定义矛盾。

    查询 (u) 是否是 (P) 中某个点的祖先:找到 (P) 中第一个满足 (st_v>st_u)(v)。因为欧拉序有一个性质:两个点代表的区间要不然一个包含一个,要不然不相交,所以只需要判断 (ed_v) 是否小于 (ed_u) 即可。

    对于删除操作,每次添加操作修改的点个数是 (O(1)) 的,因此在 (S) 中每个点上记录修改即可。

    代码
    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <vector>
    #include <set>
    using namespace std;
    #define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
    #define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
    template<typename T> void Read(T &x){
    	x=0;int _f=1;
    	char ch=getchar();
    	while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
    	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    	x=x*_f;
    }
    template<typename T,typename... Args> void Read(T &x,Args& ...others){
    	Read(x);Read(others...);
    }
    typedef long long ll;
    const int Inf=0x3f3f3f3f,N=3e5+5;
    int Kase,n;
    vector<int> S[N],T[N];
    int st[N],ed[N],dfx=0;
    void Dfs(int u){
    	st[u]=++dfx;
    	for(int v:T[u]){Dfs(v);}
    	ed[u]=++dfx;
    }
    struct Clique{
    	struct Cmp{
    		bool operator()(int x,int y) const{return st[x]<st[y];}
    	};
    	set<int,Cmp> clq;
    	bool SonOf(int u){
    		auto it=clq.upper_bound(u);
    		if(it==clq.end()) return 0;
    		return ed[*it]<ed[u];
    	}
    	int AncOf(int u){
    		auto it=clq.upper_bound(u);
    		if(it==clq.begin()) return 0;
    		int v=*--it;
    		return (st[v]<st[u]&&ed[u]<ed[v])?v:0;
    	}
    	void Add(int u,int &add,int &del){
    		if(SonOf(u)) return;
    		int v=AncOf(u);
    		if(v) clq.erase(v),del=v;
    		clq.insert(u),add=u;
    	}
    }c;
    int ans=0;
    void Work(int u){
    	int ad=0,dl=0;
    	c.Add(u,ad,dl);ans=max(ans,static_cast<int>(c.clq.size()));
    	for(int v:S[u]) Work(v);
    	if(ad) c.clq.erase(ad);
    	if(dl) c.clq.insert(dl);
    }
    int main(){
    	Read(Kase);
    	while(Kase--){
    		ans=dfx=0;c.clq.clear();
    		Read(n);
    		For(i,1,n) S[i].clear(),T[i].clear();
    		int x;
    		For(i,2,n){
    			Read(x);S[x].push_back(i);
    		}
    		For(i,2,n){
    			Read(x);T[x].push_back(i);
    		}
    		Dfs(1);
    		Work(1);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    Written by Alan_Zhao
  • 相关阅读:
    数据库的优化(非连接查询和连接查询的巧用)
    sql中为表添加一个含有括号的字段
    如何在有int型主键遍历表中的某一列数据
    三层架构的基本例子
    委托和事件
    sql中的常见函数
    博客园图灵杯第3届博问大赛(8.28~9.28)
    程序员部落酋长 Joel 之洞见
    安全领域多位世界级权威的智慧结晶——《黑客新型攻击防范:深入剖析犯罪软件》
    图灵“微软四大技术秘籍”近期出版!
  • 原文地址:https://www.cnblogs.com/alan-zhao-2007/p/vp-cf-722-div2.html
Copyright © 2011-2022 走看看