【Luogu P3950】部落冲突

Problem

Description

给出一棵树。

你需要处理下面三件事,所有的事件都是按照时间顺序给出的。

  1. \(Q, u, v\) 代表询问 \(u, v\) 之间能否相互到达
  2. \(C, u, v\) 代表 \(u, v\) 之间的边断开了
  3. \(U, x\) 代表第 \(U\) 次 \(C\) 操作被还原

Input Format

第一行两个数 \(n\) 和 \(m\) , \(n\) 代表了一共有 \(n\) 个部落,\(m\) 代表了以上三种事件发生的总数

接下来的 \(n - 1\) 行,每行两个数 \(p, q\) ,代表了第 \(p\) 个点与第 \(q\) 个点之间有一条道路相连

接下来的 \(m\) 行,每行表示一个操作,详见题目描述。

Output Format

对于每个 \(Q\) 操作都给出一行 YesNo 代表询问结果。

Range

\(n, m\le 3*10^5\)

Algorithm

树状数组

Mentality

其实本来是想练手一下 \(LCT\) 的,但是这题用 \(LCT\) 实在显得牛刀杀鸡 ……

大致看了一下题解,都用了树剖和 \(LCT\) 这样的,但其实有一种很简单的方法,只需要树状数组 + 随机数。

根据题目,对于一条路径 \(u, v\) ,这条路径联通当且仅当 \(u, v\) 上的边都没有被断开。

那么如何才能满足这个条件呢?换成对断边的要求,就是对于当前所有断开了的边,\(u, v\) 要么都在它的子树内,要么都不在。

则我们可以考虑用 \(dfn\) 序 + 树状数组维护子树信息,只要在每次断边的时候,给子树内每个点都赋上一个特有信息,然后询问的时候对 \(u, v\) 查询上面的信息是否相等即可。

如何赋上这个特殊信息呢?很简单,对于每次断边都 \(rand\) 一个特定权值,用树状数组给子树内的所有节点都加上这个权值即可。

查询的时候只需要查一下两点权值是否相同就行。

还原的时候再删掉就好了。

Code

#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
#define LL long long
#define go(G, x, i, v)   for (int i = G.hd[x], v = G.to[i]; i; v = G.to[i = G.nx[i]])
#define inline __inline__ __attribute__((always_inline))
inline LL read() {
  LL x = 0, w = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') w = -1;
    ch = getchar();
  }
  while (isdigit(ch)) {
    x = (x << 3) + (x << 1) + ch - '0';
    ch = getchar();
  }
  return x * w;
}

const int Max_n = 3e5 + 5, mod = 998244353;
int n, m;
int cntd, dep[Max_n], dfn[Max_n], siz[Max_n];
int c[Max_n];
struct graph {
  int hd[Max_n];
  int cntr, nx[Max_n << 1], to[Max_n << 1];
  void addr(int u, int v) {
    cntr++;
    nx[cntr] = hd[u], to[cntr] = v;
    hd[u] = cntr;
  }
} G;
struct que {
  int u, v, x;
} k[Max_n];

namespace Input {
void main() {
  n = read(), m = read();
  int u, v;
  for (int i = 1; i < n; i++) {
    u = read(), v = read();
    G.addr(u, v), G.addr(v, u);
  }
}
}  // namespace Input

namespace Init {
void build(int x, int fa) {
  dep[x] = dep[fa] + 1, siz[x] = 1, dfn[x] = ++cntd;
  go(G, x, i, v) if (v != fa) build(v, x), siz[x] += siz[v];
}
void main() { build(1, 0); }
}  // namespace Init

namespace Solve {
void add(int k, int x) {
  for (int i = k; i <= n; i += i & -i) (c[i] += x) %= mod;
}
int query(int k) {
  int ans = 0;
  for (int i = k; i; i -= i & -i) (ans += c[i]) %= mod;
  return (ans + mod) % mod;
}
void main() {
  srand((unsigned)time(NULL));
  int cnt = 0, u, v;
  char op;
  for (int i = 1; i <= m; i++) {
    scanf(" %c", &op);
    u = read();
    if (op == 'U')
      add(dfn[k[u].v], -k[u].x), add(dfn[k[u].v] + siz[k[u].v], k[u].x);
    else {
      v = read();
      if (op == 'Q')
        printf("%s\n", query(dfn[u]) == query(dfn[v]) ? "Yes" : "No");
      else {
        k[++cnt].x = rand() % mod;
        if (dep[u] > dep[v]) swap(u, v);
        add(dfn[v], k[cnt].x), add(dfn[v] + siz[v], -k[cnt].x);
        k[cnt].u = u, k[cnt].v = v;
      }
    }
  }
}
}  // namespace Solve

int main() {
#ifndef ONLINE_JUDGE
  freopen("3950.in", "r", stdin);
  freopen("3950.out", "w", stdout);
#endif
  Input::main();
  Init::main();
  Solve::main();
}

原文地址:https://www.cnblogs.com/luoshuitianyi/p/12147126.html

时间: 2024-11-07 09:51:08

【Luogu P3950】部落冲突的相关文章

【luogu P3950 部落冲突】 题解

题目连接:https://www.luogu.org/problemnew/show/P3950 1.像我这种学数据结构学傻了的 2.边权化点权 所有点权初始化0 3.对于战争 将深度较深的-1,对于和平 将深度较深的+1 4.对于历史 用war记录 5.特别注意 在两个查询的LCA处判断是否为-1并且当前的整条路径上的点权也为-1时 同样是yes 代码: include include include include define lson left, mid, rt<<1 define r

P3950 部落冲突

\(\color{#0066ff}{ 题目描述 }\) 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多可歌可泣的动人故事. 其中,在大大小小的部落之间,会有一些道路相连,这些道路是Travian世界里的重要枢纽,简单起见,你可以把这些部落与部落之间相连的道路看作一颗树,可见每条道路对于Travian世界的重要程度.有了这些道路,建筑工人就可以通过这些道路

计算部落冲突时长的工具

今天闲来无事,想找一个计算部落冲突建筑升级时间.发现没有得心应手的,就自己写了一个控制台输出的小程序. import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; public class T5 { public static void main(String[] args) { //获取当前系统毫秒 Date nowDate=new Date(System.currentTimeMill

部落冲突(Clash of Clans)12月更新官方资料:可掠夺资源比例调整的详细说明

部落冲突(Clash of Clans)12月更新官方资料:可掠夺资源比例调整的详细说明 们决定要调整战斗中可掠夺资源的比例了! 不要担心,冷静,冷静,再冷静,然后深呼吸,吸气,呼气-- 本次调整后的可掠夺资源计算办法实在是太复杂了,就这个题目写上一篇论文,发表在权威杂志也绰绰有余了,不过如果要长话短说的话就是: "玩家都将体会到更加容易积累与大本营级别相匹配的丰富资源,从而建造和升级昂贵的建筑,研究昂贵的兵种和法术.同时,通过调整不同大本营等级的可掠夺资源比例,你将会更容易找到大鱼."

Cogs 2856. [洛谷U14475]部落冲突

2856. [洛谷U14475]部落冲突 ★★★   输入文件:lct.in   输出文件:lct.out   简单对比时间限制:1 s   内存限制:256 MB [题目描述] 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多可歌可泣的动人故事. 其中,在大大小小的部落之间,会有一些道路相连,这些道路是Travian世界里的重要枢纽,简单起见,你可以把这

部落冲突云手机多开改不同IP防检测挂机

现在很多手游工作室采用云手机多开这个技术挂机一个可以赚金的手游,云手机相当于一个虚拟手机的存在.云手机顾名思义是与云技术有关,但我不想讲的那么高深,大家可以百度一下阿里云,腾讯云等服务器了解一下,云手机就是云服务器下的虚拟框架手机.(安卓系统)可以叫它云手机,也可以叫它云平板.它不是手游模拟器,也不是真实手机.下面,小编我以<部落冲突>为例进行代练的操作示范 首先,安装部落冲突手游,以360版本为例,在360手游市场中搜索并安装<部落冲突>.这时,您可以启动并运行<部落冲突&

[Luogu] 部落冲突--00

https://www.luogu.org/problemnew/show/P3950 思路简单,树剖不用动脑子 #include <bits/stdc++.h> using namespace std; const int N = 3e5 + 10; #define gc getchar() #define lson jd << 1 #define rson jd << 1 | 1 struct Node_1{ int v, nxt; }G[N << 1]

题解【部落冲突】

LCT学习ing……从FlshHu的大佬的博客中看到此题,于是便写了一下. 题目背景 在一个叫做Travian的世界里,生活着各个大大小小的部落.其中最为强大的是罗马.高卢和日耳曼.他们之间为了争夺资源和土地,进行了无数次的战斗.期间诞生了众多家喻户晓的英雄人物,也留下了许多可歌可泣的动人故事. 其中,在大大小小的部落之间,会有一些道路相连,这些道路是Travian世界里的重要枢纽,简单起见,你可以把这些部落与部落之间相连的道路看作一颗树,可见每条道路对于Travian世界的重要程度.有了这些道

Luogu P1692 部落卫队

解题思路 数据范围不是很大,那应该不是那些普遍的图论的算法.考虑搜索,用暴力解决.从1到N枚举每一个点的位置,搜索这个点事选还是不选.如果在这个点之前选到的点中又和他冲突的点,那就不选,要么就选. 附上代码 #include <cstdio> #include <cstring> #include <iostream> using namespace std; int n, m, cnt[103], Ans[103], ans[103], res; bool dis[1