# CSP-S-2020

## T1 Julian day

Give the highest respect (kowtow) to the T1 author.

## T2 Zoo

Give some numbers, guarantee\(x∈[1,2^k-1]\)And different from each other, some conditions are given if there are numbers\(x\)The first\(ai\)Bit is\(1\)Then you have to choose the item\(bi\)，\(bi\)They are different. How many numbers are there\(y\)Satisfaction does not exist\(x=y\)And add\(y\)Post selected\(b\)unchanged.

It is easy to find that if a condition is not satisfied, there is no number\(x\)The first\(ai\)If the bit is 1, then the selected number is\(ai\)Bits must also be 0. For the given\(k\)Positions, assuming that the bits that must be 0 have\(c\)Then there are the rest\(2^{k-c}\)The number will not change after adding\(b\)The selection of. And subtract the given\(n\)The number is the answer.

\(n=0,k=64\)We need to judge the situation. Remember to open\(unsigned\) \(long\) \(long\)。

```
#include
using namespace std;
#define ll unsigned long long
const int N=1e6+5;
int n,m,c,k;
ll now,t[70];
int a[N];
int main()
{
scanf("%d %d %d %d",&n,&m,&c,&k);
t[0]=1;
for(int i=1;i<=k;++i) t[i]=t[i-1]*2;
now=0;ll x;
for(int i=1;i<=n;++i)
{
scanf("%llu",&x);
now|=x;
}
for(int i=1,b;i<=m;++i) scanf("%d %d",&a[i],&b);
sort(a+1,a+m+1);
a[0]=unique(a+1,a+m+1)-a-1;
int tmp=k;
for(int i=1;i<=a[0];++i)
{
if(a[i]>=tmp) break;
if((now&t[a[i]])==0) k--;
}
if(k==64&&n==0) printf("18446744073709551616");
else printf("%llu",(ll)t[k]-n);
return 0;
}
```

## T3 function call

I feel that this problem should be the last word. How can it be T3.

### 30pts

It is good to think of the method of line segment tree + recursion. The line segment tree only maintains the product. Each time 1 operation is performed, the product is multiplied from the line segment tree, and then 1 operation is performed\(O(logn)\), 2 operation is directly multiplied at the root node of the line segment tree, and the implementation is O (1).

```
#include
using namespace std;
#define ll long long
const int N=1e5+5,M=1e6+5;
const ll mod=998244353;
int n,m,Q;
int tot,cz3[M];
struct node{int op,x,y;}cz[N];
ll val[N],mul[N<<2];
void Build(int l,int r,int p)
{
mul[p]=1;
if(l==r) return;
int mid=(l+r)>>1;
Build(l,mid,p<<1);
Build(mid+1,r,p<<1|1);
return;
}
void Spread(int p)
{
if(mul[p]==1) return;
int l=p<<1,r=p<<1|1;
mul[l]=mul[l]*mul[p]%mod;
mul[r]=mul[r]*mul[p]%mod;
mul[p]=1;
return;
}
void Change(int l,int r,int x,ll y,int p)
{
if(l==r)
{
val[l]=(val[l]*mul[p]+y)%mod;
mul[p]=1;
return;
}
Spread(p);
int mid=(l+r)>>1;
if(x<=mid) Change(l,mid,x,y,p<<1);
else Change(mid+1,r,x,y,p<<1|1);
return;
}
void Update(int l,int r,int p)
{
if(l==r)
{
val[l]=val[l]*mul[p]%mod;
return;
}
Spread(p);
int mid=(l+r)>>1;
Update(l,mid,p<<1);
Update(mid+1,r,p<<1|1);
return;
}
void Calc(int pos)
{
if(cz[pos].op==1) Change(1,n,cz[pos].x,(ll)cz[pos].y,1);
else if(cz[pos].op==2) mul[1]=mul[1]*cz[pos].x%mod;
else
{
for(int i=cz[pos].x;i<=cz[pos].y;++i)
Calc(cz3[i]);
}
return;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&val[i]);
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
scanf("%d",&cz[i].op);
if(cz[i].op==1) scanf("%d %d",&cz[i].x,&cz[i].y);
else if(cz[i].op==2) scanf("%d",&cz[i].x);
else
{
scanf("%d",&Q);
cz[i].x=tot+1;
for(int j=1;j<=Q;++j) scanf("%d",&cz3[tot+j]);
cz[i].y=(tot+=Q);
}
}
Build(1,n,1);
scanf("%d",&Q);
for(int i=1,x;i<=Q;++i)
{
scanf("%d",&x);
Calc(x);
}
Update(1,n,1);
for(int i=1;i<=n;++i) printf("%lld ",val[i]);
return 0;
}
```

### 100pts

If the line segment tree method fails to operate in 3, it can call 3 operation, and many repeated calculations will be carried out. For example, 5 calls 2, 8 calls 5 (2, 5, 8 is the number). Finally, the operation sequence given is: 258, then the operation order is: 2528 552. Repeated calls stack up the time.

The idea of full score is extension and complement sorting. Each operation is superimposed on the operation calling it. The time complexity is\(O(n)\)It’s not easy to understand.

**This method separates addition from multiplication.**

For example: suppose there is only one number\(2\), first\(*3\)Operation, and then\(+1\), and then\(*2\)According to the previous idea, the calculation process is\((2*3+1)*2\)After taking apart addition and multiplication, the calculation process becomes\(2*3*2+1*2\)。

Since each multiplication is applied to the entire array, the expansion times of each number are the same for the given array at the beginning, so run all operations once\(ai=k*ai\)。

**So let’s talk about the multiplication part first, that is, how to find this quickly\(k\)。**

#### Multiplication Section

First of all, we should understand that the final q is followed by a bunch of operations, which can be regarded as a 3-operation, that is, calling other functions, assuming the number is\(m+1\)。

Therefore, if all operations are connected to the operation calling it, a certain acyclic directed graph can be obtained. (if there is a ring, i.e\(a\)call\(b\)，\(b\)call\(a\), will fall into an endless loop)

An example diagram is given (to facilitate understanding, the call sequence is assumed to be from left to right)

Because each operation will be affected by the operation after it is invoked, the reverse operation can guarantee that no operation can affect the operation after that.

such as\(*3\)If the product in the blue box is\(*5\)So now the product of the whole graph should be\(*3*15\)。 (corresponding to yellow road and purple Road)

You can see that,\(*3\)and\(*5\)The product of the whole graph obtained by first calculating which operation is the same. Therefore, in the product, the left and right order is not important for the same operation. You only need to ensure that all sub operations are completed when the operation is in progress.

(for example, in the example given, in the blue box, the bottom three points must be calculated first to get the values of the two points above, then the two points can be used to contribute to the upper point\(*5\)）

All the rules that can be added to the queue with the input degree of 0 can be used to get the operation order.

Then, according to this operation order, each point contributes the product to the connected points.

For the operation that is not used, there is no path node to\(m+1\)All its contributions are not cumulative\(k\)Inside.

Code implementation (when writing code, my side is from side operation to sub operation, all statistics are\(out\)）：

```
inline void add(int u,int v)
{
out[u]++;G[u].push_back(v);F[v].push_back(u);
}
void Init()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
scanf("%d %d",&cz[i].op,&cz[i].x);
if(cz[i].op==1) scanf("%d",&cz[i].y);
else if(cz[i].op==3) for(int j=1,v;j<=cz[i].x;++j) scanf("%d",&v),add(i,v);
}
m++;
scanf("%d",&Q);
for(int i=1,v;i<=Q;++i) scanf("%d",&v),add(m,v);
}
void Topo()
{
int l=1;
for(int i=1;i<=m;++i)
if(!out[i]) tq[++tq[0]]=i;
while(l<=tq[0])
{
int u=tq[l++];
int S=F[u].size();
for(int i=0;i
```

#### Addition part

As shown in the figure, the blue box represents many operations (node 2 has operations before node 1, node 3 also has operations before node 2. If the above figure is too messy, it is not drawn).

Suppose that the cumulative value of 2 nodes is 6 and that of 3 nodes is 10.

Suppose there’s one here\(+5\)Is affected by the later operations. The number added will become\(5*60+5*30+5*15\)。 (blue, green, pink).

It can be seen that 1 is directly connected to 4 nodes. At this time, the product of 23 accumulated is 60, so 1 node accumulates 60.

One is connected to two nodes, but there are two types of two nodes.

Two nodes are directly connected to four nodes. In this case, the product of 3 accumulation is 10, so 2 nodes accumulate 10.

Two nodes are connected to three nodes, and three nodes are connected to four nodes. There is no subsequent impact on three nodes. At this time, the cumulative value of root node is 1, so 3 accumulates 1. At this time, there is a follow-up of three nodes\(*5\)In this case, the product accumulated to 4 is 1, so 5 is accumulated at 2.

So the cumulative value of 2 is\(10+5\)。

1 at 2 will be\(*3\)So the cumulative value of 1 is\(60+30+15\)。

In this way, it seems to be a recursive operation, but in fact, it can be seen as a descending operation from top to bottom. The implementation is extremely simple and the code is very short.

```
for(int i=tq[0];i;--i)
for(int j=G[tq[i]].size()-1,ml=1;j>=0;--j)
{
mul[G[tq[i]][j]]=((ll)ml*mul[tq[i]]+mul[G[tq[i]][j]])%mod;
ml=(ll)ml*sum[G[tq[i]][j]]%mod;
}
for(int i=1;i<=n;++i) a[i]=a[i]*sum[m]%mod;
for(int i=1;i
```

Put in the complete code:

```
#include
using namespace std;
#define ll long long
const int N=1e5+5;
const ll mod=998244353;
int n,m,Q,out[N],tq[N];
ll a[N],mul[N],sum[N];
struct node{int op,x,y;}cz[N];
vectorG[N],F[N];
inline void add(int u,int v)
{
out[u]++;G[u].push_back(v);F[v].push_back(u);
}
void Init()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
scanf("%d %d",&cz[i].op,&cz[i].x);
if(cz[i].op==1) scanf("%d",&cz[i].y);
else if(cz[i].op==3) for(int j=1,v;j<=cz[i].x;++j) scanf("%d",&v),add(i,v);
}
m++;
scanf("%d",&Q);
for(int i=1,v;i<=Q;++i) scanf("%d",&v),add(m,v);
}
void Topo()
{
int l=1;
for(int i=1;i<=m;++i)
if(!out[i]) tq[++tq[0]]=i;
while(l<=tq[0])
{
int u=tq[l++];
int S=F[u].size();
for(int i=0;i=0;--j)
{
mul[G[tq[i]][j]]=((ll)ml*mul[tq[i]]+mul[G[tq[i]][j]])%mod;
ml=(ll)ml*sum[G[tq[i]][j]]%mod;
}
for(int i=1;i<=n;++i) a[i]=a[i]*sum[m]%mod;
for(int i=1;i
```

## T4 greedy snake

If B is eaten by another snake, B will not eat it. If all snakes are not smart, then if a ate another snake and a ate B, then a would not eat B because it would be eaten by other snakes after eating B. So when each snake eats another snake, it stores it. If the snake doesn’t eat it, there are still several snakes left. If the snake eats the first snake that has eaten other snakes, it will return to the storage value of this one.

It can be used\(set\), balance tree to quickly insert and delete.

But the time complexity is not a, you can get most points.

Every time the snake is eaten, it must be the snake in the initial array. Therefore, the snake eaten must be strictly increased. This increase means that the snake is sorted according to the size of the question.

Another array q is opened to store the value of a after eating B. each time the snake takes out to eat other snakes, it must be strictly decreasing, so the value obtained after eating is also strictly decreasing, which ensures the monotonicity of Q. Each time the largest value is either Q or in the original array, and the smallest one can only be in the original array. If the minimum value of Q is smaller than the original array, the calculation is over.