来一发大暴力
树链剖分无疑了 对于某个询问节点,二分答案所在的深度,若该深度到该节点上的区间和>0,说明其中有满足条件的点,增加深度继续二分,否则减小深度线段树上的操作:单点修改+区间查询(区间和)
关于时间:
时间复杂度\(O(nlog^{2}n)\)
虽然不是最优解法,但能过了,稍微卡一下,总时间大概900ms,最大点300ms,如果\(O(nlogn)\)的玩家太注重卡常的话还是可以碾的,当然我的代码还有优化余地...(比如传参部分可以用空间换时间,卡常玩家可以尝试一下(还有fread之类的都可以尝试一下))关于最优解法:我有一个绝妙的思路,这里篇幅太小写不小,你可以看别人的题解
#include#include #include #define writeln(x) write(x),puts("")using namespace std;inline int read(){ int ans=0,f=1;char chr=getchar(); while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();} while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} return ans*f;}void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0');}const int M=100005;char opt[2];int head[M<<1],ver[M<<1],x,y,nxt[M<<1],tot,n,m,dep[M],fa[M],tp[M],sz[M],son[M],idx[M],s[M<<2],rk[M];inline void add(int x,int y){ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;}void dfs1(int x,int f){ sz[x]=1;dep[x]=dep[f]+1,fa[x]=f; for(register int i=head[x];i;i=nxt[i]){ if(!dep[ver[i]]){ dfs1(ver[i],x),sz[x]+=sz[ver[i]]; if(sz[son[x]] >1)inline void Push_Up(int i){s[i]=s[ls]+s[rs];}void Update(int i,int l,int r,int pos,int x){ if(l==r){s[i]=x;return;} if(pos<=mid) Update(ls,l,mid,pos,x); else Update(rs,mid+1,r,pos,x); Push_Up(i);}int Query(int i,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr) return s[i];int ans=0; if(ql<=mid) ans+=Query(ls,l,mid,ql,qr); if(qr>mid) ans+=Query(rs,mid+1,r,ql,qr); return Push_Up(i),ans;}inline void Ask(int x){ if(Query(1,1,n,idx[x],idx[x])) {cout< < >1; if(Query(1,1,n,midd,rr)) ans=midd,ll=midd+1; else rr=midd-1; }return (void)(writeln(rk[ans])); } }}int main(){ n=read(),m=read(); for(register int i=1;i