P3942将军令

题目传送P3942

思路

  • P2279消防局的设立的加强版
  • 我们只需要每次找到最深的点,然后找到向上距离他 \(k\) 个深度的祖先
  • 话说只要在之前的代码改几个地方就行
  • 可我偏偏调了一晚上
  • 数据到了1e5
  • 到大数据就莫名死循环
  • 改了下
  • 还是TLE
  • TLE的原因 是每次把选中点距离为 \(k\) 的点标记,要记录前一个点,而不能直接用它的父亲,因为并不准确,我们可能向下走也可能向上走,上一个走过来的不一定是父亲。需要单独记录。
  • 死循化 的原因好像是弹出队列时死循环了

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<vector>
#pragma GCC optimize(2)
using namespace std;
int n,tot,ans,k,t;
bool vis[100005];
int head[100005];

int dep[100005],fa[100005];
struct node{
	int to,net;
}e[200005];
struct cmp{
	bool operator () (int &a,int &b){
		return dep[a]<dep[b];
	}
};
priority_queue<int,vector<int>,cmp>q;
inline void add(int x,int y){
	e[++tot].to =y,e[tot].net=head[x],head[x]=tot;
	e[++tot].to =x,e[tot].net=head[y],head[y]=tot;
}
inline void dfs1(int x,int f,int depth){
	fa[x]=f;
	dep[x]=depth;
	for(int i=head[x];i;i=e[i].net ){
		int to=e[i].to ;
		if(to==f) continue;
		dfs1(to,x,depth+1);
	}
}
inline void dfs2(int x,int from,int depth){
	if(depth>k) return ;
	vis[x]=1;
	for(int i=head[x];i;i=e[i].net ) 
	  if(e[i].to !=from)dfs2(e[i].to ,x,depth+1);
}
void cal(int x){
	int num=0;
	while(num<k){
		num++;
		x=fa[x];
	}
	t=x;
	/*if(x==0) {
		t=x;
		return ;
	}
	if(num==k){
		t=x;
		return ;
	}
	cal(fa[x],num+1);*/
}
inline int read(){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w; 
} 
int main()
{
//	freopen("63.in","r",stdin);
//	freopen("63.out","w",stdout);
	n=read();k=read();t=read();
//    scanf("%d%d%d",&n,&k,&t);
	for(int i=1;i<n;i++){
		int x,y;
		x=read();y=read(); 
//        scanf("%d%d",&x,&y); 
		add(x,y);
	} 
	dfs1(1,0,1);
	for(int i=1;i<=n;i++) q.push(i);
	int x;
	while(q.size()){
		x=q.top() ;q.pop();
		if(vis[x]) continue ;
//		while(q.size()&&vis[x=q.top()]) q.pop();
//		cout<<"DE"<<endl;
		cal(x);
		if(t) dfs2(t,t,0);
		else dfs2(1,1,0); 
		ans++;
	}
	printf("%d",ans);
	return 0; 
 } 
posted @ 2019-09-11 19:34  _Vimin  阅读(170)  评论(0编辑  收藏  举报