题解:

我的做法好像跟网上不太一样。。

首先分位讨论

我的做法是先观察出了一个性质

这个答案只跟最后一个0出现的位置有关(这个随便yy一下很容易出来因为运算有0则1)

然后问题就变成了

给出一棵树,支持单点修改,查询x向上第一个0的位置

其实这个用lct维护比较方便。。而且这个复杂度是nlog^2的 我有空写下比较一下时间。。

我写的是nlog^3的树剖维护。。注意到路径有向所以还要分情况分开写(第一次写)

所以lct写起来应该非常简单。。。。除了updata改改其他就是模板了。。

主要是这段时间在做线段树没想lct。。。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define IL inline
#define rint register int
#define mid ((h+t)/2)
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
char ss[<<],*A=ss,*B=ss;
IL char gc()
{
return (A==B&&(B=(A=ss)+fread(ss,,<<,stdin),A==B)?EOF:*A++);
}
template<class T>void read(T &x)
{
rint f=,c; while (c=gc(),c<||c>) if (c=='-') f=-; x=c^;
while (c=gc(),<c&&c<) x=(x<<)+(x<<)+(c^); x*=f;
}
void read2(char* x)
{
string s;
char c;
while (c=gc(),c!=' ') s+=c;
strcpy(x,s.c_str());
}
char sr[<<],z[]; int C=-,Z;
template <class T> void wer(T x)
{
if (x<) sr[++C]='-',x=-x;
while (z[++Z]=x%+,x/=);
while (sr[++C]=z[Z],--Z); sr[++C]='\n';
}
IL int max(int x,int y)
{
if (x>y) return(x); else return(y);
}
IL int min(int x,int y)
{
if (x<y) return(x); else return(y);
}
IL void swap(int &x,int &y)
{
int tmp=x; x=y; y=tmp;
}
IL bool odd(int x)
{
if (x%==) return(); else return();
}
const int N=1.1e5;
char s[];
int l,head[N],v[N],fa[N],son[N],size[N],dfn[N],top[N],real2[N],dep[N],num,n,m,k;
struct re{
int a,b,c;
}a[N*];
void arr(int x,int y)
{
a[++l].a=head[x];
a[l].b=y;
head[x]=l;
}
void dfs1(int x,int y)
{
fa[x]=y; size[x]=; son[x]=; dep[x]=dep[y]+;
int u=head[x];
while (u)
{
int v=a[u].b;
if (v!=y)
{
dfs1(v,x);
size[x]+=size[v];
if (size[v]>size[son[x]]) son[x]=v;
}
u=a[u].a;
}
}
void dfs2(int x,int y)
{
dfn[x]=++num; real2[num]=x;
top[x]=y; if(!son[x]) return;
dfs2(son[x],y);
int u=head[x];
while (u)
{
int v=a[u].b;
if (v!=fa[x]&&v!=son[x]) dfs2(v,v);
u=a[u].a;
}
}
struct sgt{
int f[N*];
sgt()
{
rep(i,,N*-) f[i]=;
}
IL void updata(int x)
{
f[x]=f[x*]&f[x*+];
}
void insert(int x,int h,int t,int pos,int k)
{
if (h==t)
{
f[x]=k; return;
}
if (pos<=mid) insert(x*,h,mid,pos,k);
else insert(x*+,mid+,t,pos,k);
updata(x);
}
vector<re> ve;
void query5(int x,int h,int t,int h1,int t1)
{
if (h1<=h&&t<=t1)
{
ve.push_back((re){x,h,t});
return;
}
if (h1<=mid) query5(x*,h,mid,h1,t1);
if (mid<t1) query5(x*+,mid+,t,h1,t1);
}
int query3(int x,int h,int t)
{
if (h==t) return(real2[h]);
if (!f[x*]) return(query3(x*,h,mid));
else return(query3(x*+,mid+,t));
}
int query4(int x,int h,int t)
{
if (h==t) return(real2[h]);
if (!f[x*+]) return(query4(x*+,mid+,t));
else return(query4(x*,h,mid));
}
int query1(int x,int h,int t,int h1,int t1)
{
ve.clear();
query5(x,h,t,h1,t1);
dep(i,ve.size()-,)
if (!f[ve[i].a]) return(query4(ve[i].a,ve[i].b,ve[i].c));
return(-);
}
int query2(int x,int h,int t,int h1,int t1)
{
ve.clear();
query5(x,h,t,h1,t1);
rep(i,,ve.size()-)
if (!f[ve[i].a]) return(query3(ve[i].a,ve[i].b,ve[i].c));
return(-);
}
int query(int x,int y)
{
int x1=x,x2,x3=y;
vector<re> v1,v2;
int f1=top[x],f2=top[y];
while (f1!=f2)
{
if (dep[f1]<dep[f2])
{
v2.push_back((re){y,f2});
y=fa[f2]; f2=top[y];
} else
{
v1.push_back((re){x,f1});
x=fa[f1]; f1=top[x];
}
}
if (dep[x]<dep[y]) v2.push_back((re){y,x}),x2=x;
else v1.push_back((re){x,y}),x2=y;
rint ans;
// rep(i,0,(v1.size()-1))
for (int i=;i<v1.size();i++)
{
ans=query1(,,n,dfn[v1[i].b],dfn[v1[i].a]);
if (ans!=-) return(!odd(dep[x1]-dep[ans]));
}
for (int i=v2.size()-;i>=;i--)
{
ans=query2(,,n,dfn[v2[i].b],dfn[v2[i].a]);
if (ans!=-) return(!odd(-*dep[x2]+dep[x1]+dep[ans]));
}
return(!odd(dep[x1]+dep[x3]-*dep[x2]));
}
}sgt[];
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
read(n); read(m); read(k);
rep(i,,n) read(v[i]);
rep(i,,n-)
{
int x,y; read(x); read(y);
arr(x,y); arr(y,x);
}
dfs1(,); dfs2(,);
rep(i,,k-)
rep(j,,n)
sgt[i].insert(,,n,dfn[j],(v[j]>>i)&);
rep(i,,m)
{
int x,y;
read2(s); read(x); read(y);
if (s[]=='Q')
{
ll ans=;
rep(j,,k-)
ans+=1ll*sgt[j].query(y,x)*(1ll<<j);
wer(ans);
} else
{
rep(j,,k-)
sgt[j].insert(,,n,dfn[x],(y>>j)&);
}
}
fwrite(sr,,C+,stdout);
return ;
}

 正解:

其实正解很简单啊。。。

首先分位讨论和我一样

然后每次进去只有0/1两种

所以直接上线段树就可以了

但是这样也是nlog^3的(比我写的这个应该要简单啊,不用线段树二分了)

我们考虑优化一下

我们把进去的状态加一个 (1<<k)-1(这个还是非常巧妙的)

我们需要进去的时候对(1<<k)-1 的值and一下 因为只有两个都为1之后才会为1

而对于0的值我们需要取反再and

这样就做到了nlog^2(这个一定是可以碾压lct的)

bzoj2908的更多相关文章

  1. 【BZOJ2908】又是nand 树链剖分+线段树

    [BZOJ2908]又是nand escription 首先知道A nand B=not(A and B) (运算操作限制了数位位数为K)比如2 nand 3,K=3,则2 nand 3=not (2 ...

  2. BZOJ2908: 又是nand

    Description 首先知道A nand B=not(A and B) (运算操作限制了数位位数为K)比如2 nand 3,K=3,则2 nand 3=not (2 and 3)=not 2=5. ...

  3. LCT专题练习

    [bzoj2049]洞穴勘测 http://www.cnblogs.com/Sdchr/p/6188628.html 小结 (1)LCT可以方便维护树的连通性,但是图的连通性的维护貌似很麻烦. [bz ...

  4. 【BZOJ4811】[Ynoi2017]由乃的OJ 树链剖分+线段树

    [BZOJ4811][Ynoi2017]由乃的OJ Description 由乃正在做她的OJ.现在她在处理OJ上的用户排名问题.OJ上注册了n个用户,编号为1-",一开始他们按照编号排名. ...

随机推荐

  1. 《转》return *this和 return this有什么区别?

    别跟我说 return *this 表示返回当前对象,return this 表示返回当前对象的地址(指向当前对象的指针). 正确答案为:return *this 返回的是当前对象的克隆或者本身(若返 ...

  2. CTex+WinEdt10.2安装详细教程与破解

    原文地址:https://www.cnblogs.com/xiachongkun/p/8176390.html Latex作为目前最好用的文档编排工具,以前只是简单会一点,现在也已经忘得差不多了.因为 ...

  3. IEnumerable和IEnumerator使用

    IEnumerable接口是非常的简单,只包含一个抽象的方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象. IEnumerator是一个真正的集合访问器,没 ...

  4. vue.js computed,watch的区别

    computed: 当数据没有变化时,它会去读取缓存,当数据有变化时,它才会去执行computed,而不会像method和watch一样每次都去执行函数(摘自https://www.jb51.net/ ...

  5. java结合testng,利用excel做数据源的数据驱动实例

    数据驱动部分,是自动化测试常用部分,也是参数化设计的重要环节,前面分享了,mysql.yaml做数据源,那么再来分享下excel做数据驱动 思路: 先用POI读取excel.解析读取数据,返回list ...

  6. 自然语言处理之LCS最长公共子子序列

    #!一个序列S任意删除若干个字符得到的新序列T,则T叫做S的子序列 注意,这个和最长公共字串不一样,最长公共子串要求连续. 1.算法公式: def lcs(a,b): lena = len(a) le ...

  7. vue入手

    https://www.jianshu.com/p/dc5057e7ad0d    (最全入坑教程) http://doc.liangxinghua.com/vue-family/1.4.html(v ...

  8. 基于AD5663的UV灯电压控制

    在开发臭氧发生器的时,我们使用UV灯来实现臭氧的产生.而UV灯的强度决定了臭氧产生的浓度,UV灯的光强则与其控制电压密切相关.所以我们要控制产生的臭氧的浓度就需要调节其控制电压.我们选择了AD5663 ...

  9. SQL Server 数据恢复到指点时间点(完整恢复)

    SQL Server 数据恢复到指点时间点(完整恢复) 高文龙关注2人评论944人阅读2017-03-20 12:57:12 SQL Server 数据恢复到指点时间点(完整恢复) 说到数据库恢复,其 ...

  10. windows+mysql集群搭建-三分钟搞定集群

    注:本文来源:  陈晓婵   <  windows+mysql集群搭建-三分钟搞定集群   > 一:mysql集群搭建教程-基础篇 计算机一级考试系统要用集群,目标是把集群搭建起来,保证一 ...