E(pbds)

题意:

  

  1<=m,n<=5e5

分析:

  首先指向关系形成了一个基环外向树森林

  实际上我们可以完全不用真正的去移动每个球,而只需要在计数的时候考虑考虑就行了

  对于树上的情况,我们假设在时间为now的时候在距离根为dis的点上放了个球,我们记录下now+dis

  对于询问树上的情况,即查找在时间为i的时候有多少个球会到达x点,那么我们只需要考虑以x为根的子树里(now+dis==i+d[x])的个数即可,很显然这可以用dfs序+数据结构来搞

  这个数据结构需要支持单点修改、询问区间内某一数字出现了多少次

  树状数组+主席树?

  我们换个角度,因为数字都不大,我们不妨对于每个数字都开一个set,查找就是在对应数字里的set里查找[l,r]中的数字有多少个,这个用pbds里的set就行了

  还有一个case,如果询问在环上咋办?

  我们可以记录每个球来到环上的时间,对于每个环直接用带模数组维护即可

 #include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#define mp make_pair
using namespace std;
using namespace __gnu_pbds;
const int inf=;
typedef tree<pair<int,int>,null_type,less<pair<int,int> >,rb_tree_tag,tree_order_statistics_node_update> rbtree;
const int maxn=5e5;
int f[maxn+],fa[maxn+],c[maxn+],len[maxn+];
int L[maxn+],R[maxn+],dep[maxn+],root[maxn+],id[maxn+];
int n,m,ans,dfn,color;
vector<int> g[maxn+];
rbtree rbt[*maxn+];
multiset<pair<int,int> > s;
map<int,int> a[maxn+];
int find(int k)
{
if(f[k]==k) return k;
return f[k]=find(f[k]);
}
void addedge(int u,int v)
{
g[u].push_back(v);
}
void dfs(int k)
{
L[k]=++dfn;
for(auto u:g[k])
{
if(c[u]) continue;
dep[u]=dep[k]+;
root[u]=root[k];
dfs(u);
}
R[k]=dfn;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i) f[i]=i;
for(int i=;i<=n;++i) scanf("%d",&fa[i]),addedge(fa[i],i);
for(int i=;i<=n;++i)
{
int u=find(i),v=find(fa[i]);
if(u!=v)
{
f[u]=v;
continue;
}
u=fa[i];
++color;
int tmp=;
while(true)
{
++len[color];
c[u]=color;
id[u]=tmp++;
u=fa[u];
if(u==fa[i]) break;
}
}
for(int i=;i<=n;++i)
if(c[i]) root[i]=i,dfs(i);
scanf("%d",&m);
for(int i=;i<=m;++i)
{
int x;
scanf("%d",&x);
x^=ans;
if(c[x])
{
s.insert(mp(i,x));
while(!s.empty())
{
pair<int,int> u=*s.begin();
if(u.first>i) break;
int color=c[u.second];
++a[color][(u.first-id[u.second]+len[color])%len[color]];
s.erase(s.begin());
}
int color=c[x];
ans=a[color][(i-id[x]+len[color])%len[color]];
printf("%d\n",ans);
}
else
{
rbt[i+dep[x]].insert(mp(L[x],i));
ans=rbt[i+dep[x]].order_of_key(mp(R[x],inf))-rbt[i+dep[x]].order_of_key(mp(L[x],-inf));
printf("%d\n",ans);
s.insert(mp(i+dep[x],root[x]));
}
}
return ;
}

F(数据结构)

题意:

  

  

分析:

  首先不考虑修改,对于一个给定的数组a,我们如何快速求出需要执行多少次操作才能把它全部变成0?

  我们可以发现以下的性质:

    1、有些位置对最终答案满贡献,其它位置对最终答案0贡献

    2、极大值对最终答案是满贡献的

    3、我们从初始的所有极大值开始每次隔1个数,直到遇到边界或者极小值,那么数到的数都会在过程中成为极大值

    4、若一个极小值对答案有贡献,那么它到两边的极大值的距离都为偶数

  于是我们就可以O(n)解决了

  但是现在有修改操作,我们来考虑如何在之前信息的基础上维护一些东西

  求答案的本质是找到那些极大值极小值,然后从极大值开始间隔1个数,我们可以用两个树状数组来维护奇数位/偶数位上的前缀和

  然后我们用一个set去存下所有的极大值、极小值

  对于一个修改(x,y)

  我们找到一个set里的极小区间[l,r],使得l和r的极大极小性质一定不会被破坏

  然后把这段区间对答案的贡献减掉

  然后修改a[x]->y

  再把这段区间对答案的贡献加上去

  时间复杂度O(nlogn)

 #include<bits/stdc++.h>
using namespace std;
typedef set<int>::iterator iter;
typedef long long ll;
const int maxn=1e5;
ll c[][maxn+];
ll a[maxn+];
int n;
ll ans=;
set<int> s;
int lowbit(int x)
{
return x&(-x);
}
void add(ll *c,int k,ll x)
{
for(;k<=n/+;k+=lowbit(k)) c[k]+=x;
}
void add(int k,ll x)
{
if(k&) add(c[],(k+)>>,x);else add(c[],(k+)>>,x);
}
ll query(ll *c,int k)
{
ll ans=;
for(;k;k-=lowbit(k)) ans+=c[k];
return ans;
}
ll query(ll *c,int l,int r)
{
if(l>r) return ;
return query(c,r)-query(c,l-);
}
int type(int id)
{
if(a[id-]<a[id]&&a[id]>=a[id+]) return ;
if(a[id-]>=a[id]&&a[id]<a[id+]) return -;
return ;
}
ll cal(int l,int r)
{
if(r-l<) return ;
if(a[l]<a[r])
{
int R=(r+)/-;
int L;
if((l&)==(r&)) L=(l+)/+;else L=(l+)/;
return query(c[r&],L,R);
}
else
{
int L=(l+)/+;
int R;
if((l&)==(r&)) R=(r+)/-;else R=r/;
return query(c[l&],L,R);
}
}
ll cal(iter l,iter r)
{
ll ans=;
for(iter i=l;i!=r;++i)
{
iter tmp=i;
++tmp;
ans+=cal(*i,*tmp);
}
++r;
for(iter i=l;i!=r;++i)
if(type(*i)==) ans+=a[*i];
else
if(type(*i)==-)
{
iter tmp1=i,tmp2=i;
--tmp1,++tmp2;
if((*tmp2-*i)%==&&(*i-*tmp1)%==) ans+=a[*i];
}
else
{
iter tmp=i;
if(*i==) ++tmp;else --tmp;
if((*tmp-*i)%==) ans+=a[*i];
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%lld",&a[i]),add(i,a[i]);
s.insert(),s.insert(n);
for(int i=;i<n;++i)
if(type(i)!=) s.insert(i);
iter tmp=s.end();
ans=cal(s.begin(),--tmp);
int q;
scanf("%d",&q);
for(int i=;i<=q;++i)
{
int x;ll y;
scanf("%d%lld",&x,&y);
int l=x-,r=x+;
if(r>n-) r=n-;
if(l<) l=;
iter L=s.lower_bound(l);
--L;
iter R=s.upper_bound(r);
ans-=cal(L,R);
int left=*L,right=*R;
add(x,y-a[x]);
a[x]=y;
if(type(x)!=) s.insert(x);
else if(s.count(x)&&x>=&&x<=n-) s.erase(x);
if(x+<n)
if(type(x+)==&&s.count(x+)) s.erase(x+);
else if(type(x+)!=) s.insert(x+);
if(x->)
if(type(x-)==&&s.count(x-)) s.erase(x-);
else if(type(x-)!=) s.insert(x-);
L=s.lower_bound(left);
R=s.lower_bound(right);
ans+=cal(L,R);
printf("%lld\n",ans);
}
return ;
}

Wannafly挑战赛16的更多相关文章

  1. Wannafly 挑战赛16 A 取石子

    题目描述 给出四堆石子,石子数分别为a,b,c,d.规定每次只能从堆顶取走石子,问取走所有石子的方案数. 输入描述: 在一行内读入四个由空格分隔的整数a,b,c,d, 输入均为不超过500的正整数 输 ...

  2. Wannafly挑战赛16 #E 弹球弹弹弹 splay+基环树+各种思维

    链接:https://ac.nowcoder.com/acm/problem/16033来源:牛客网 有n个位置,标号为1到n的整数,m次操作,第i次操作放置一个弹球在b[i] xor c[i-1]处 ...

  3. Wannafly 挑战赛 19 参考题解

    这一次的 Wannafly 挑战赛题目是我出的,除了第一题,剩余的题目好像对大部分算法竞赛者来说好像都不是特别友好,但是个人感觉题目质量还是过得去的,下面是题目链接以及题解. [题目链接] Wanna ...

  4. Wannafly挑战赛25游记

    Wannafly挑战赛25游记 A - 因子 题目大意: 令\(x=n!(n\le10^{12})\),给定一大于\(1\)的正整数\(p(p\le10000)\)求一个\(k\)使得\(p^k|x\ ...

  5. Wannafly挑战赛27

    Wannafly挑战赛27 我打的第一场$Wannafly$是第25场,$T2$竟然出了一个几何题?而且还把我好不容易升上绿的$Rating$又降回了蓝名...之后再不敢打$Wannafly$了. 由 ...

  6. Wannafly挑战赛21A

    题目链接 Wannafly挑战赛21A 题解 代码 #include <cstdio> #include <cmath> #define MAX 1000005 #define ...

  7. Wannafly挑战赛24游记

    Wannafly挑战赛24游记 A - 石子游戏 题目大意: A和B两人玩游戏,总共有\(n(n\le10^4)\)堆石子,轮流进行一些操作,不能进行下去的人则输掉这局游戏.操作包含以下两种: 把石子 ...

  8. Wannafly挑战赛25C 期望操作数

    Wannafly挑战赛25C 期望操作数 简单题啦 \(f[i]=\frac{\sum_{j<=i}f[j]}{i}+1\) \(f[i]=\frac{f[i]}{i}+\frac{\sum_{ ...

  9. Wannafly挑战赛18B 随机数

    Wannafly挑战赛18B 随机数 设\(f_i\)表示生成\(i\)个数有奇数个1的概率. 那么显而易见的递推式:\(f_i=p(1-f_{i-1})+(1-p)f_{i-1}=(1-2p)f_{ ...

随机推荐

  1. java做http接口

    问题描述 我要对外提供一个http接口给别人调用...但是我不知道用java怎么做这个接口.请大家详细给我讲讲.从开发到如何发布到服务器.谢谢了 解决方案 如果你这个很简单的话,而且数量也很少,建议直 ...

  2. graph-basic

    打算使用STL中的vector,通过邻接链表的方式存储图.这里贴基本定义,以及depth-first-search和breadth-first-search的实现代码. 其他图的算法实现,就贴在各自的 ...

  3. UVA - 11572 Unique Snowflakes 滑动扫描

    题目:点击打开题目链接 思路:从左往右扫描,定义扫描左端点L,右端点R,保证每次往几何中添加的都是符合要求的连续的数列中的元素,L和R从0扫到n,复杂度为O(n),使用set维护子数列,set查找删除 ...

  4. hdu 5533

    Dancing Stars on Me Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Ot ...

  5. Android兼容性测试CTS Verifier-环境搭建、测试执行、结果分析

    CTS Verifier算是CTS的一部分,需要手动进行,主要用于测试那些自动测试系统无法测试的功能,比如相机.传感器等.由于硬件配置或其他原因,不同手机上部分测试项目被隐藏,也就是说CTS Veri ...

  6. 修改Echarts 图表的坐标轴的文本的排列位置

    option.xAxis.axisLabel['interval'] = 0 option.xAxis.axisLabel['formatter'] = function(value,index){ ...

  7. Python的内存管理、命名规则、3个特性讲解

    理解变量: 变:现实世界中的状态是会发生改变的 量:衡量/记录现实世界中的状态,让计算机能够像人一样去识别世间万物(例如:一个人的身高.体重等这些信息) 为什么要变量: 程序执行的本质就是一系列状态的 ...

  8. 开发者工具删除元素Delete Element

    开发者工具有个很好用的功能,通过删除元素,可以查看页面哪些元素比较特殊,同时也可以排除干扰.

  9. [SDOI2013]直径 (树的直径,贪心)

    题目链接 Solution 我们直接找到一条直径 \(s\),起点为 \(begin\),终点为 \(end\). 从前往后遍历点 \(u\) ,若子树中最大的距离与 \(dis(u,begin)\) ...

  10. [转] Makefile 基础 (9) —— Makefile 使用make更新函数库文件

    该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...