• UTR #1摸鱼解题报告


    UTR #1摸鱼解题报告

    前言

    最近刷uoj题,感觉古代大佬们都好强。。。

    vfk的数据

    链接

    http://uoj.ac/problem/9

    题解

    一个普通的排序题,直接贴代码了。

    (Code)

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    struct ZFC{
    	string s;
    	int L;
    }s[10005];
    bool cmp(ZFC A,ZFC B){
    	if(A.L==B.L) return A.s<B.s;
    	return A.L<B.L;
    }
    int main(){
    	cin>>n;
    	for(int i=1;i<=n;++i) {
    		cin>>s[i].s;
    		s[i].L=s[i].s.length();
    	}
    	sort(s+1,s+1+n,cmp);
    	for(int i=1;i<=n;++i) cout<<s[i].s<<endl;
    	return 0;
    } 
    
    

    pyx的难题

    链接

    http://uoj.ac/problem/10

    题解

    如果已知优先级,然后模仿整个过程是(O(nlogn))的。
    于是不难想到一个二分答案的(O(nlog^{2}n))的做法。然而过不了。
    然后我就卡在这了。。。
    “第一问的二分是建立在单调性上的,而有单调性的题,往往可以试着利用扫描的方法去优化。”(题解原话)
    感觉这个思路并不新,但经常会忘记有这种方向。。然而确实是很实用的一种思路。
    然后把二分换成扫描就降了一个log下来,就能过了。

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=3e5+10;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    int n;
    LL sss,ttt;
    struct node{
    	int t,s,p,id,v;
    	LL L;
    }a[N];
    bool cmp(node A,node B){
    	return A.p<B.p;
    }
    bool cmp2(node A,node B){
    	return A.t<B.t;
    }
    bool cmp3(node A,node B){
    	return A.id<B.id;
    }
    map<int,int> num,pi;
    priority_queue< pair<int,int> > Q;
    void J(LL l,LL r,int pp){
    	int x=num[pp];
    	if(l<sss) l=sss;
    	if(r>ttt) r=ttt;
    	if(l<=r) a[x].L+=r-l+1; 
    }
    LL ans[N];
    int main(){
    	pair<int,int> z;
    	n=read();
    	for(int i=1;i<=n;++i) {
    		a[i].t=read();a[i].s=read();a[i].p=read();
    		a[i].id=i;
    		if(a[i].p==-1) sss=a[i].t;
    	}
    	scanf("%lld",&ttt);--ttt;
    	sort(a+1,a+1+n,cmp2);
    	for(int i=1;i<=n;++i){
    		num[a[i].p]=i;a[i].v=i;
    	}
    	LL now=0,tt;
    	for(int i=1;i<=n;++i){
    		while(now<a[i].t&&(!Q.empty())){
    			z=Q.top();Q.pop();
    			tt=min((LL)z.second,(LL)a[i].t-now);
    			J(now,now+tt-1,z.first);
    			now=now+tt;z.second=z.second-tt;
    			if(z.second) Q.push(z);
    		}
    		if(now<a[i].t) now=a[i].t;
    		Q.push(make_pair(a[i].p,a[i].s));
    	}
    	
    	while(!Q.empty()){
    		z=Q.top();Q.pop();
    		tt=z.second;
    		J(now,now+tt-1,z.first);
    		now=now+tt;
    	}
    	sort(a+1,a+1+n,cmp);
    	LL w=0;int y;
    	for(int i=1;i<=n;++i){
    		w=w+a[i].L;
    		y=max(1,a[i].p+1);
    		if(num[y]) continue;
    		if(w==a[1].s) {
    			a[1].p=y;break;
    		}
    	}
    	cout<<a[1].p<<endl;
    	num[a[1].p]=num[-1];a[1].v=num[-1];
    	for(int i=1;i<=n;++i) {
    		y=a[i].v;
    		while(i!=a[i].v){
    			swap(a[i],a[y]);
    			y=a[i].v;
    		}
    	}
    	now=0;
    	for(int i=1;i<=n;++i){
    		while(now<a[i].t&&(!Q.empty())){
    			z=Q.top();Q.pop();
    			tt=min((LL)z.second,(LL)a[i].t-now);
    			now=now+tt;z.second=z.second-tt;
    			if(z.second) Q.push(z);
    			else{
    				ans[a[num[z.first]].id]=now;
    			}
    		}
    		if(now<a[i].t) now=a[i].t;
    		Q.push(make_pair(a[i].p,a[i].s));
    	}
    	while(!Q.empty()){
    		z=Q.top();Q.pop();
    		tt=z.second;
    		now=now+tt;
    		ans[a[num[z.first]].id]=now;
    	}
    	for(int i=1;i<=n;++i) {
    		print(ans[i]);putchar(' ');
    	}
    	puts("");
    	return 0;
    }
    

    ydc的大树

    链接

    http://uoj.ac/problem/11

    题解

    这道题要用到树的中心的概念。
    树的任何一个点的最远点一定是某条直径的端点。通过这个性质可以(O(n))找直径。
    树的直径可能有多个(这个显然,参考菊花树)。
    取某条直径,找到直径的最中间的点,这个点不一定是树的节点,也可能是边上的某点,记这个点是树的中心。
    有一个性质:任何一个点走到最远点一定经过中心。
    由于中心可以在边上,那样的话那条边的两个端点就必然被经过了。

    然后再这道题中,如果我们把中心或中心所在边上的某端点取出来作为根,就会有神奇的性质。
    所有黑点到它的好朋友的路径一定经过根节点。
    显然,如果把一条路径从根节点分成两段,第一段就是走到根,第二段就是找个最深黑点走。
    然后这题就变成了一个大讨论题。。
    首先我们考虑如果最后答案是0,那么方案数一定是n-m。
    然后我们只考虑能让黑点不高兴的情况。
    如果断点是根,这个情况挺好写的不说了。
    若最深黑点分布在至少3颗子树中,我们只需考虑每个白点的子树内黑点数即可。
    若最深黑点分布在恰好2颗子树中,没有最深黑点的子树像第一种情况来就好,然后剩余两颗子树之间再讨论。
    (由于以上两种数据听特殊的,似乎uoj里数据没有上面两种情况)
    然后只有一颗子树内有最深黑点时,在这颗子树内的黑点要找的其他“最深点”要另外再找一遍。
    如果断点在这颗子树中,我们只需看它是否覆盖到所有最深黑点进行讨论。
    如果断点在其他子树中,我们要找到次深黑点再讨论,具体不赘述了,看代码吧。

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=1e5+10;
    const int INF=1e9;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    int n,m,cnt=1;
    int col[N],bl[N],dis[N],hed[N],las[N];
    struct edge{
    	int r,nxt,w;
    }e[N<<1];
    void insert(int u,int v,int w){
    	e[++cnt].r=v;e[cnt].nxt=hed[u];hed[u]=cnt;e[cnt].w=w;
    }
    int rt;
    int q[N];
    void dij(){
    	int l=1,r=1;q[1]=rt;
    	fill_n(dis,N,INF);
    	dis[rt]=0;
    	while(l<=r){
    		int y=q[l++];
    		for(int i=hed[y];i;i=e[i].nxt){
    			if(dis[e[i].r]>dis[y]+e[i].w){
    				las[e[i].r]=y;
    				dis[e[i].r]=dis[y]+e[i].w;
    				q[++r]=e[i].r;
    			}
    		}
    	}
    	return;
    }
    int mxd[N],fa[N],dep[N];
    void dfs(int x){
    	if(col[x]) mxd[x]=dep[x];
    	for(int i=hed[x];i;i=e[i].nxt){
    		if(fa[x]!=e[i].r){
    			fa[e[i].r]=x;
    			dep[e[i].r]=dep[x]+e[i].w;
    			dfs(e[i].r);
    			mxd[x]=max(mxd[x],mxd[e[i].r]);
    		}
    	}
    }
    int mx=0;
    int ans1=0,ans2=0;
    void upd(int x){
    	if(x<=0) return;
    	if(x>ans1){ans1=x;ans2=1;}
    	else if(x==ans1) ++ans2;
    }
    int sz[N],son[N];
    void getval(int x){
    	sz[x]=col[x];
    	if(col[x]==1&&dep[x]==mx) son[x]=1;
    	for(int i=hed[x];i;i=e[i].nxt){
    		if(e[i].r!=fa[x]){
    			getval(e[i].r);
    			sz[x]+=sz[e[i].r];
    			son[x]+=son[e[i].r];
    		}
    	}
    }
    void DP(int x,int op,int y,int z){
    	for(int i=hed[x];i;i=e[i].nxt){
    		if(e[i].r!=fa[x]){
    			DP(e[i].r,op,y,z);
    		}
    	}
    	if(col[x]==0){
    		if(op==3){upd(sz[x]);return;}
    		if(op==2){
    			if(son[x]==son[y]) upd(sz[x]+m-sz[y]);
    			else upd(sz[x]);
    			return;
    		}
    		if(op==1){
    			if(son[x]==son[y]) upd(sz[x]+sz[z]);
    			else upd(sz[x]);
    			return;
    		}
    	}
    }
    int main(){
    	int u,v,w;
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i){
    		bl[i]=read();
    		col[bl[i]]=1;
    	}
    	for(int i=1;i<n;++i){
    		u=read();v=read();w=read();
    		insert(u,v,w);
    		insert(v,u,w);
    	}
    	rt=bl[1];
    	dij();
    	for(int i=1;i<=m;++i){
    		if(dis[bl[i]]>dis[rt]) rt=bl[i];
    	}
    	dij();
    	u=rt;v=rt;
    	for(int i=1;i<=m;++i){
    		if(dis[bl[i]]>dis[v]) v=bl[i];
    	}
    	double D=dis[v]*1.0/2;
    	while(dis[las[v]]>=D) v=las[v];
    	rt=v;
    	dfs(rt);
    	for(int i=1;i<=m;++i) mx=max(mx,mxd[bl[i]]);
    	int k=0;
    	for(int i=hed[rt];i;i=e[i].nxt) if(mxd[e[i].r]==mx) ++k;
    	if(k>=3) k=3;
    	ans1=0;ans2=n-m;
    	if(col[rt]==0)upd(m);
    	getval(rt);
    	if(k==2){
    		u=0;v=0;
    		for(int i=hed[rt];i;i=e[i].nxt) {
    			if(mxd[e[i].r]==mx){
    				if(!u) u=e[i].r;
    				else v=e[i].r;
    			} 
    		}
    	}
    	for(int i=hed[rt];i;i=e[i].nxt) {
    		if(k==3)DP(e[i].r,3,e[i].r,0);
    		if(k==2&&mxd[e[i].r]!=mx) DP(e[i].r,3,e[i].r,0);
    		if(k==2&&mxd[e[i].r]==mx) DP(e[i].r,1,e[i].r,(e[i].r^u^v));
    		if(k==1&&mxd[e[i].r]==mx) DP(e[i].r,2,e[i].r,0);
    	}
    	if(k==1){
    		u=0;v=0;
    		for(int i=hed[rt];i;i=e[i].nxt) {
    			if(mxd[e[i].r]==mx){
    				u=e[i].r;
    			} 
    		}
    		v=mx;
    		mx=0;
    		for(int i=hed[rt];i;i=e[i].nxt){
    			if(mxd[e[i].r]!=v){
    				mx=max(mx,mxd[e[i].r]);
    			}
    		}
    		k=0;
    		for(int i=hed[rt];i;i=e[i].nxt) if(mxd[e[i].r]==mx) ++k;
    		if(mx>0){
    			if(k==1){
    				for(int i=hed[rt];i;i=e[i].nxt){
    					if(mxd[e[i].r]<mx) DP(e[i].r,3,e[i].r,0);
    				}
    				getval(rt);
    				for(int i=hed[rt];i;i=e[i].nxt){
    					if(mxd[e[i].r]==mx) DP(e[i].r,1,e[i].r,u);
    				}
    			}
    			else{
    				for(int i=hed[rt];i;i=e[i].nxt){
    					if(mxd[e[i].r]<=mx) DP(e[i].r,3,e[i].r,0);
    				}
    			}
    		}
    	}
    	printf("%d %d
    ",ans1,ans2);
    	return 0;
    }
    
  • 相关阅读:
    HDOJ2036 改革春风吹满地
    NYOJ3 多边形重心问题
    HDOJ1085Holding BinLaden Captive!(母函数做法)
    SQL Server2005杂谈(5):将聚合记录集逆时针和顺时针旋转90度(行列互换)
    使用wxWidgets进行跨平台的C++开发
    SQL Server2005杂谈(2):公用表表达式(CTE)的递归调用
    HeadFirst设计模式学习笔记(C#版):鸭子与策略(Strategy)模式
    选择创业项目的基础——适合自己的才是最好的
    博客也是网络赚钱的有利工具
    SQL Server2005杂谈(1):使用公用表表达式(CTE)简化嵌套SQL
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/13721216.html
Copyright © 2020-2023  润新知