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

原文地址:https://www.cnblogs.com/Vimin/p/11508242.html

时间: 2024-08-30 17:55:10

P3942的相关文章

luogu P3942 将军令

题目背景 pdf题面和大样例链接:http://pan.baidu.com/s/1cawM7c 密码:xgxv 历史/落在/赢家/之手 至少/我们/拥有/传说 谁说/败者/无法/不朽 拳头/只能/让人/低头 念头/却能/让人/抬头 抬头/去看/去爱/去追 你心中的梦 题目描述 又想起了四月. 如果不是省选,大家大概不会这么轻易地分道扬镳吧? 只见一个又一个昔日的队友离开了机房. 凭君莫话封侯事,一将功成万骨枯. 梦里,小 F 成了一个给将军送密信的信使. 现在,有两封关乎国家生死的密信需要送到前

P3942 将军令

P3942 将军令 梦里,小 F 成了一个给将军送密信的信使. 现在,有两封关乎国家生死的密信需要送到前线大将军帐下,路途凶险,时间紧迫.小 F 不因为自己的祸福而避趋之,勇敢地承担了这个任务. 不过,小 F 实在是太粗心了,他一不小心把两封密信中的一封给弄掉了. 小 F 偷偷打开了剩下的那封密信.他 发现一副十分详细的地图,以及几句批文--原来 这是战场周围的情报地图.他仔细看后发现,在这张地图上标记了 n 个从 1 到 n 标号的 驿站,n ? 1 条长度为 1 里的小道,每条小道双向连接两

将军令 Luogu P3942

pdf题面和大样例链接:http://pan.baidu.com/s/1cawM7c 密码:xgxv 历史/落在/赢家/之手 至少/我们/拥有/传说 谁说/败者/无法/不朽 拳头/只能/让人/低头 念头/却能/让人/抬头 抬头/去看/去爱/去追 你心中的梦 将军令 题目描述 又想起了四月. 如果不是省选,大家大概不会这么轻易地分道扬镳吧? 只见一个又一个昔日的队友离开了机房. 凭君莫话封侯事,一将功成万骨枯. 梦里,小 F 成了一个给将军送密信的信使. 现在,有两封关乎国家生死的密信需要送到前线

【贪心】P3942 将军令 &amp;&amp; P2279 消防局的设立

1.消防局的设立 题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构.如果基地A到基地B至少要经过d条道路的话,我们称基地A到基地B的距离为d. 由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局.消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过2的基地的火灾. 你的任务是计算至少要修建多少个消防局才能够确保火星上所有

【bzoj3940】[Usaco2015 Feb]Censoring

[题目描述] FJ把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过10^5的字符串S.他有一个包含n个单词的列表,列表里的n个单词 记为t_1...t_N.他希望从S中删除这些单词. FJ每次在S中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从S中删除这个单词.他重复这个操作直到S中 没有列表里的单词为止.注意删除一个单词后可能会导致S中出现另一个列表中的单词 FJ注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在S中出现的开始位置是

P4392 [BOI2007]静音问题 题解

传送门:P3942 这道题要求我们对所有长度为m的序列,找出其中最大值和最小值的差值不超过c的,并输出它们的起始位置. 看到静态序列最值问题,很自然的想到要用ST表进行Θ(nlogn+n)预处理.Θ(1)查询.但是很不幸,如果直接用两个表分别存储最大值和最小值,最后一个点妥妥的MLE,因此我们需要对空间占用进行优化. 考虑到每个序列的长度是固定的,我们可以先进行一次ST表操作,记录下vali= max{ai →ai+m} .再在同一个f数组中进行第二次ST表操作,计算出fi = min{ai →