首页 > 其他分享 >The 2024 ICPC Asia EC Regionals Online Contest (II) - Problem B. Mountain Booking

The 2024 ICPC Asia EC Regionals Online Contest (II) - Problem B. Mountain Booking

时间:2024-09-21 23:24:04浏览次数:9  
标签:Mountain Contest int seg ce II vip continue include

从 $1$ 到 $m$ 依次考虑每个日期。假设当前正在考虑第 $i$ 天,那么只有第 $i$ 天来访的游客以及指定第 $i$ 天的查询是有用的。将这些游客和查询都提取出来,通过 Kruskal 重构树可以很方便地在 $O(n\log n)$ 的时间内计算出这些查询的答案。

不幸的是,本题还有加边删边操作,无法轻易地动态维护 Kruskal 重构树。解决问题的关键是注意到假设第 $i$ 天有 $t_i$ 个游客、$q_i$ 个询问,那么可以支付 $O((t_i+q_i)\log n)$ 的代价来获取它们对应的节点形成的大小为 $O(t_i+q_i)$ 的虚树,然后在虚树上暴力构建 Kruskal 重构树计算每个询问的答案。

求虚树的方法很多,比如 LCT 或者离线分治。假设 $n,m,p,q$ 同阶,总时间复杂度为 $O(n\log n)$。

 

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100005,M=200005,Q=200005,K=19;
vector<int>gt[M],gq[M];
struct Qry{int x;ll ans;}qry[Q];
struct E{int x,y,w;}e[K][N],edge[N];
namespace Inner{
int f[N<<1],tour[N<<1];ll sum[N<<1];
inline bool cmp(const E&a,const E&b){return a.w<b.w;}
int F(int x){
  if(f[x]==x)return x;
  int y=f[x];
  f[x]=F(f[x]);
  sum[x]+=sum[y];
  return f[x];
}
inline void solve(int n,int m,int d){
  int i;
  for(i=1;i<=n;i++){
    f[i]=i;
    tour[i]=sum[i]=0;
  }
  for(const auto&o:gt[d])tour[o]++;
  sort(edge+1,edge+m+1,cmp);
  for(i=1;i<=m;i++){
    int x=edge[i].x,y=edge[i].y,w=edge[i].w;
    x=F(x),y=F(y);
    int z=n+i;
    sum[x]=1LL*w*tour[y];
    sum[y]=1LL*w*tour[x];
    sum[z]=0;
    f[x]=f[y]=f[z]=z;
    tour[z]=tour[x]+tour[y];
  }
  for(const auto&o:gq[d]){
    int x=qry[o].x;
    F(x);
    qry[o].ans=sum[x];
  }
}
}
struct Seg{int x,y,w,l,r;}seg[K][N+M];
int n,m,ct,cq,ce,i,x,y,z,o;
int g[N],v[N<<1],w[N<<1],nxt[N<<1],ed,fa[N],wei[N],id[N],vip[N];bool vis[N];
inline void add(int x,int y,int z){
  v[++ed]=y;
  w[ed]=z;
  nxt[ed]=g[x];
  g[x]=ed;
}
inline void addedge(int x,int y,int z){
  add(x,y,z);
  add(y,x,z);
}
inline void newedge(int x,int y,int z){
  edge[++ed].x=x;
  edge[ed].y=y;
  edge[ed].w=z;
}
void compress(int x,int y){
  int d=0;
  id[x]=0;
  vis[x]=1;
  for(int i=g[x];i;i=nxt[i]){
    int u=v[i];
    if(u==y)continue;
    fa[u]=x;
    wei[u]=w[i];
    compress(u,x);
    if(!id[u])continue;
    d++;
    id[x]^=id[u];
  }
  if(d>1)vip[x]=1;
  if(vip[x]){
    for(int i=g[x];i;i=nxt[i]){
      int u=v[i];
      if(u==y)continue;
      int t=id[u];
      if(!t)continue;
      int mx=0;
      for(int j=t;j!=x;j=fa[j])if(mx<wei[j])mx=wei[j];
      newedge(x,t,mx);
    }
    id[x]=x;
  }
}
void solve(int d,int l,int r,int ce,int n,int m){
  int i;
  ed=0;
  for(i=1;i<=n;i++)vip[i]=vis[i]=g[i]=0;
  for(i=1;i<=m;i++)addedge(e[d][i].x,e[d][i].y,e[d][i].w);
  for(i=1;i<=ce;i++){
    if(seg[d][i].r<l||seg[d][i].l>r)continue;
    if(seg[d][i].l<=l&&seg[d][i].r>=r){
      addedge(seg[d][i].x,seg[d][i].y,seg[d][i].w);
      continue;
    }
    vip[seg[d][i].x]=vip[seg[d][i].y]=1;
  }
  for(i=l;i<=r;i++){
    for(const auto&o:gt[i])vip[o]=1;
    for(const auto&o:gq[i])vip[qry[o].x]=1;
  }
  ed=0;
  for(i=1;i<=n;i++)if(vip[i]&&!vis[i])compress(i,0);
  int _n=0;
  for(i=1;i<=n;i++)if(vip[i])vip[i]=++_n;
  if(_n<=1)return;
  n=_n;
  m=ed;
  for(i=1;i<=m;i++){
    edge[i].x=vip[edge[i].x];
    edge[i].y=vip[edge[i].y];
  }
  for(i=l;i<=r;i++){
    for(auto&o:gt[i])o=vip[o];
    for(const auto&o:gq[i])qry[o].x=vip[qry[o].x];
  }
  if(l==r){
    Inner::solve(n,m,l);
    return;
  }
  int _ce=0;
  for(i=1;i<=m;i++)e[d+1][i]=edge[i];
  for(i=1;i<=ce;i++){
    if(seg[d][i].r<l||seg[d][i].l>r)continue;
    if(seg[d][i].l<=l&&seg[d][i].r>=r)continue;
    seg[d+1][++_ce].x=vip[seg[d][i].x];
    seg[d+1][_ce].y=vip[seg[d][i].y];
    seg[d+1][_ce].w=seg[d][i].w;
    seg[d+1][_ce].l=seg[d][i].l;
    seg[d+1][_ce].r=seg[d][i].r;
  }
  int mid=(l+r)>>1;
  solve(d+1,l,mid,_ce,n,m);
  solve(d+1,mid+1,r,_ce,n,m);
}
int main(){
  ios_base::sync_with_stdio(0);cin.tie(0);
  cin>>n>>m>>ct>>cq;
  for(i=1;i<n;i++){
    cin>>x>>y>>z;
    seg[0][i].x=x;
    seg[0][i].y=y;
    seg[0][i].w=z;
    seg[0][i].l=1;
    seg[0][i].r=m;
  }
  ce=n-1;
  for(i=1;i<=m;i++){
    cin>>o>>x>>y>>z;
    seg[0][o].r=i-1;
    seg[0][++ce].x=x;
    seg[0][ce].y=y;
    seg[0][ce].w=z;
    seg[0][ce].l=i;
    seg[0][ce].r=m;
  }
  for(i=1;i<=ct;i++){
    cin>>o>>x;
    gt[o].emplace_back(x);
  }
  for(i=1;i<=cq;i++){
    cin>>o>>x;
    qry[i].x=x;
    gq[o].emplace_back(i);
  }
  solve(0,1,m,ce,n,0);
  for(i=1;i<=cq;i++)cout<<qry[i].ans<<"\n";
}

  

标签:Mountain,Contest,int,seg,ce,II,vip,continue,include
From: https://www.cnblogs.com/clrs97/p/18424674

相关文章

  • IIS8.0无法加载asp.net程序的解决方案
    1.更改系统文件machine.config文件,它位于C:\WINNT\Microsoft.NET\下面<configProtectedDatadefaultProvider="RsaProtectedConfigurationProvider">    <providers>      <addname="RsaProtectedConfigurationProvider"type="......
  • Atcoder Beginner Contest 372
    AtcoderBeginnerContest372A模拟即可。#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;voidsolve(){charch;while(cin>>ch){if(ch!='.'){cout<<ch;}}}......
  • AtCoder Beginner Contest 372
    省流版A.暴力即可B.转换3进制即可C.考虑答案的组成,仅修改发生变化的部分即可D.维护答案数组\(ans_i\),考虑枚举\(j\)对哪些\(i\)有贡献,通过单调栈找到对应的区间\(i\),通过差分维护区间加法即可E.并查集维护连通块,\(set\)维护点标号大小,合并\(set\)时启发式合并,查询......
  • The 2024 ICPC Asia EC Regionals Online Contest (II)
    目录写在前面F签到A枚举J贪心I构造,二进制L数学,三分G数学,辗转相除E结论,最短路写在最后写在前面补题地址:https://codeforces.com/gym/105358。以下按个人向难度排序。妈的7题秒完剩下的题感觉没一个能做的。F签到#include<bits/stdc++.h>#definelllonglongcon......
  • UNIQUE VISION Programming Contest 2024 Autumn (AtCoder Beginner Contest 372)
    总结(我的塘人局):单调栈是忘得差不多了 A-delete.题意:输出删除所有'.'的字符串思路:遍历输出不是'.'复杂度:O(n) Code:#include<bits/stdc++.h>usingnamespacestd;usingLL=longlong;usingi64=int64_t;voidsolve(){strings;cin......
  • iis服务器帝国cms7.5编辑器不能使用解决办法
    在IIS服务器上使用帝国CMS7.5时,如果编辑器不能正常使用,可能涉及多个方面的问题,包括文件权限、配置文件、依赖库等。下面是一些具体的解决办法:1.检查文件和目录权限确保帝国CMS的所有必要文件和目录具有正确的权限。步骤:检查e/data目录及其子目录:使用IISManager或其他工......
  • JAVA学习-练习试用Java实现“不同的二叉搜索树 II”
    问题:给定一个整数n,请生成并返回所有由n个节点组成且节点值从1到n互不相同的不同二叉搜索树。可以按任意顺序返回答案。示例1:输入:n=3输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]示例2:输入:n=1输出:[[1]]提示:1<=n......
  • leetcode刷题day22|回溯算法Part01( 77. 组合 、216. 组合总和 III、17.电话号码的字母
    前言:回溯是递归的副产品,只要有递归就会有回溯,回溯函数也就是递归函数。回溯是暴力穷举解法,效率并不高。但一些问题只能使用回溯来解决。回溯法,一般可以解决如下几种问题:组合问题:N个数里面按一定规则找出k个数的集合切割问题:一个字符串按一定规则有几种切割方式子集问题:一......
  • leetcode刷题day23|回溯算法Part02(39. 组合总和 、40.组合总和II、131.分割回文串)
    39.组合总和思路:这个题与77.组合的差异在于元素可以无限制重复被选取,那么只需要更改startIndex即可,每一层递归都可以从头选用元素。回溯三部曲与77.组合基本一致。代码如下:classSolution{List<List<Integer>>result=newArrayList<>();List<Integer>pa......
  • leetcode刷题day24|回溯算法Part03(93.复原IP地址、78.子集、90.子集II)
    93.复原IP地址思路:这个题和131.分割回文串一样都是对字符串进行分割,只不过这个子字符串判断时是看是不是0-225之间的数字。回溯三部曲:1、递归函数参数:全局变量:String数组result存放结果集。递归函数参数:原字符串;startIndex,因为切割过的地方不能重复切割,和组合问题是一样......