加帕里的聚会
256MB / 1s ; japari.cpp / c / pas / in / out
【题目描述】
加帕里公园里有n个区域,n-1条道路将它们连接到了一起,形成了一个树的结构。开始时,第i个区域有Ai个friends,但是由于砂之星的作用,有时从x区域到y区域的简单路径上的所有区域的friends数量都会增加v,有时从x区域到y区域的简单路径上所有区域的friends数量都会变成v。
有时,从x区域到y区域的简单路径上所有区域的friends想要聚会,聚会时需要从所有参加聚会的friends中选择一部分作为staff。加帕里的friends都很喜欢质数,因此她们希望staff和非staff的参与者的数量都是质数。
请你告诉她们,每次聚会是否存在一种方案满足她们的要求。
【输入格式】
第一行两个整数n,m,表示friends数量和事件数量。
接下来一行n个数,第i个数表示Ai。
接下来n-1行,每行2个数x,y,表示x和y之间有一条无向道路。
接下来m行,每行第一个整数opt表示事件类型。
若opt=1,接下来三个整数x,y,v,表示从x区域到y区域的简单路径上的所有区域的friends数量都增加v。
若opt=2,接下来三个整数x,y,v,表示从x区域到y区域的简单路径上的所有区域的friends数量都变为v。
若opt=3,接下来两个整数x,y,表示从x区域到y区域的简单路径上的所有区域的friends进行聚会。
【输出格式】
对于每个3事件,若可以让staff和非staff的数量都为质数,输出一行SUGOI,否则输出一行TANOSHI。
【样例数据】
japari1.in
3 4
1 2 1
2 1
3 2
2 2 1 4
1 3 3 -1
2 2 2 2
3 1 3
japari1.out
SUGOI
japari2.in
4 6
2 4 0 0
2 1
3 2
4 3
2 1 4 2
1 4 4 9
1 3 2 -2
2 4 2 5
3 1 4
3 4 4
japari2.out
TANOSHI
SUGOI
【样例解释】
在第一个样例中,三个区域的friends数量依次为4、2、0,询问的friends和为6,可以分成两组,每组的friends数量都为3。
在第二个样例中,四个区域的friends数量依次为2、5、5、5,第一个询问的friends和为17,无法分成两组。第二个询问的friends和为5,可以分为两组,每组的friends数量分别为2、3。
【数据范围】
对于30%的数据,n,m≤5000。
对于另30%的数据,对于i>1,第i个区域与第i-1个区域直接相连。
对于100%的数据,1≤n,m≤100000,1≤x,y≤n,一直满足0≤Ai,S≤10000000。在增加事件中v可能为负数。
思路:
链修改,链赋值,链求和并判断是否可以将这个和拆分为两个质数的和。直接链剖或LCT即可维护,根据哥德巴赫猜想若这个数为偶数则一定可以拆分,否则其中一个必定为2,线性筛判定质数即可。
好久没写那么长的代码了,查错能力简直low到爆。
(增值标记和赋值标记千万想清楚呀)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int lim=1e7+5,N=1e5+5,INF=0x3f3f3f3f;
bool isnot[lim];
int n,m,primed[lim/10],tot=0;
int top[N],dep[N],fa[N],son[N],siz[N],head[N],in[N],out[N],idc=0;
int seq[N],re[N],a[N],idx=0;
int sum[N<<2],sign[N<<2],flag[N<<2];
struct Edge {
int to, nxt;
}ed[N<<1];
inline void adde(int u,int v) {
ed[++idc].to = v;
ed[idc].nxt = head[u];
head[u] = idc;
}
inline void init() {
for(register int i=2; i<lim; ++i) {
if(!isnot[i]) primed[++tot]=i;
for(int j=1; j<=tot && i*primed[j]<lim; ++j) {
isnot[i*primed[j]] = true;
if(i % primed[j] == 0) break;
}
}
}
inline void dfs1(int u) {
siz[u] = 1;
for(int k=head[u]; k; k=ed[k].nxt) {
int v = ed[k].to;
if(v == fa[u]) continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1( v );
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
inline void dfs2(int u, int tp) {
seq[++idx] = u;
in[u] = idx;
top[u] = tp;
if( son[u] ) dfs2( son[u], tp );
for(int k=head[u]; k; k=ed[k].nxt) {
int v = ed[k].to;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
out[u] = idx;
}
inline void pushdown(int pos,int l, int r) {
int len = r - l + 1;
int mid = (l + r) >> 1;
if (sign[pos]!=INF) {
sign[pos<<1] = sign[pos];
sign[pos<<1|1] = sign[pos];
sum[pos<<1] = (mid-l+1) * sign[pos];
sum[pos<<1|1] = (r-mid) * sign[pos];
flag[pos<<1]=flag[pos<<1|1]=0;
sign[pos]=INF;
}
if (flag[pos]!=0) {
flag[pos<<1]+=flag[pos];
flag[pos<<1|1]+=flag[pos];
sum[pos<<1] += (mid-l+1) * flag[pos];
sum[pos<<1|1] += (r-mid) * flag[pos];
flag[pos]=0;
}
}
inline void build(int l, int r, int pos){
flag[pos] = 0; sign[pos] = INF;//
if(l == r){
sum[pos] = re[l];
return ;
}
int mid = (l + r) >> 1;
build(l, mid, pos<<1);
build(mid+1, r, pos<<1|1);
sum[pos] = sum[pos<<1] + sum[pos<<1|1];
}
inline void qu_add(int pos, int l, int r, int ll, int rr, int val){
if(ll==l && r==rr){
flag[pos] += val;
sum[pos] += (r-l+1)*val;
return;
}
pushdown(pos, l, r);
int mid = (l+r)>>1;
if(rr<=mid) qu_add(pos<<1, l, mid, ll, rr, val);
else if(ll>mid) qu_add(pos<<1|1, mid+1, r, ll, rr, val);
else{
qu_add(pos<<1, l, mid, ll, mid, val);
qu_add(pos<<1|1, mid+1, r, mid+1, rr, val);
}
sum[pos] = sum[pos<<1] + sum[pos<<1|1];
}
inline void qu_modify(int pos, int l, int r, int ll, int rr, int val){
if(ll==l && r==rr){
sign[pos] = val; /**/flag[pos] = 0;
sum[pos] = (r-l+1)*val;
return;
}
pushdown(pos, l, r);
int mid = (l+r)>>1;
if(rr<=mid) qu_modify(pos<<1, l, mid, ll, rr, val);
else if(ll>mid) qu_modify(pos<<1|1, mid+1, r, ll, rr, val);
else{
qu_modify(pos<<1, l, mid, ll, mid, val);
qu_modify(pos<<1|1, mid+1, r, mid+1, rr, val);
}
sum[pos] = sum[pos<<1] + sum[pos<<1|1];
}
inline int qu_query(int pos, int l, int r, int ll, int rr){
if(ll==l && r==rr){
return sum[pos];
}
pushdown(pos, l, r);
int mid = (l+r)>>1;
if(rr<=mid) return qu_query(pos<<1, l, mid, ll, rr);
else if(ll>mid) return qu_query(pos<<1|1, mid+1, r, ll, rr);
else return qu_query(pos<<1, l, mid, ll, mid) + qu_query(pos<<1|1, mid+1, r, mid+1, rr);
}
inline void modify(int u, int v, int val, int type) {
while (top[u] != top[v]) {
if( dep[top[u]] < dep[top[v]] ) swap(u,v);
if(type == 1) qu_add(1, 1, idx, in[top[u]], in[u], val);
else qu_modify(1, 1, idx, in[top[u]], in[u], val);
u = fa[top[u]];
}
if(dep[u] < dep[v]) swap(u,v);
if(type == 1) qu_add(1, 1, idx, in[v], in[u], val);
else qu_modify(1, 1, idx, in[v], in[u], val);
}
inline int query(int u, int v) {
int rt = 0;
while( top[u] != top[v] ) {
if( dep[top[u]] < dep[top[v]] ) swap(u,v);
rt += qu_query(1, 1, idx, in[top[u]], in[u]);
u = fa[top[u]];
}
if( dep[u] < dep[v] ) swap(u,v);
rt += qu_query(1, 1, idx, in[v], in[u]);
return rt;
}
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
int main() {
freopen("japari.in","r",stdin);
freopen("japari.out","w",stdout);
init();
n=read(), m=read();
for(register int i=1; i<=n; ++i) a[i] = read();
for(register int i=1; i<n; ++i) {
int u=read(), v=read();
adde(u,v); adde(v,u);
}
dfs1(1);
dfs2(1, 1);
for(int i=1; i<=n; i++){
re[in[i]] = a[i];
}
build(1, idx, 1);
while( m-- ){
int opt; scanf("%d", &opt);
if(opt == 1){
int x=read(), y=read(), v=read();
modify(x,y,v,1);
}
if(opt == 2){
int x=read(), y=read(), v=read();
modify(x,y,v,2);
}
if(opt == 3){
int x=read(), y=read();
int cc = query(x, y);
//judge( cc );
if (cc<4) puts("TANOSHI");
else if (cc&1) puts(isnot[cc-2]?"TANOSHI":"SUGOI");
else puts("SUGOI");
//printf("Y %d\n", cc);
}
}
return 0;
}