Taurus Link Power II

Topic links: Taurus Link Power II

Time limit: C / C ++ 1 second, other languages 2 seconds
space limitations: C / C ++ 262144K, other languages 524288K
64bit the IO the Format:% LLD
subject description
beef has a size of Magic Link-Cut array of n, each of the array node has two states, one for the link state, the other is cut state. The random array of any pair of points in the link state (i.e. (u, v) and (v, u) is considered to be of the same pair) generated link energy dis (u, v) of, dis (u, v) an array of v on u distance.

We define the entire array of energy Link energies of all nodes in the link state, link and generated.

A start state array on each node 01 by a length of size n given string, '1' indicates Link status '0' represents Cut state.

Taurus want to know the beginning, and after each operation Link entire array of energy, in order to avoid this number is too large, you only answer output in 10 9 The results can be taken after more than +7.

Input Description:
The first line enter a positive integer n (1≤n≤10 . 5 )
took the length of a line of input size in the initial state of the array 01 of n strings, '1' indicates Link status '0' represents Cut status.
The next line enter a positive integer m (1≤m≤10 . 5 number) showing the operation of the
next m lines of input two positive integers q, pos (q∈ {1,2} , 1≤pos≤n)
pos beef represents the first elements of the array operation, which value of 1, to ensure that before this operation, the element is 0 when q = 1.
Pos beef represents the first elements of the array operation, which is assigned 0, ensure, prior to this operation, the element value is 1 when q = 2.
Output Description:
Please m + 1 output line represents a start, and Link entire array of energy after each operation, in order to avoid this number is too large, you only answer output in 10 9 The results can be taken after more than +7.
Example 1
Input

5
00001
7
1 1
2 5
2 1
1 2
1 4
1 3
1 1

Export

0
4
0
0
0
2
4
10

Subject to the effect

You give a n, then there is a 01 character string of length n, you ask any distance between one and two; 1 example three bars 111, the output is 4, then you have a number of m m-per-action operations have two numbers x, y.
x = 1 y value is put into the position 1, and then outputs the sum of all distances of 1
x = 2 y value is put into the position 0, then the output of all of the distance 1 and

Problem-solving ideas

The obvious need segment tree or tree-like array to solve this I use Fenwick tree to explain. It's easy if you send a sequence, for example, is 100,101; this 01 string, if the first three position becomes 1, then more after increases how much value it generates? Produced (1,3), (3,4), (3,6); these three sections; if the fifth position becomes 1 it? So much is produced (1,5), (4,5), (5,6); We found that when we insert worth the time, will produce a new number right, for a distance before and will not change, we only before it and now we need to add it.
How to find it new? Here is the set insertion position y, above simulated by two times what I discovered a new formula for the increase is the number of y number of times y minus 1 in front after y y on the front of the prefix and suffix plus and minus multiplied by y number 1 y behind ; suffix herein and is unique location and value, for example 11011, prefixes, and sUM . 5 = 1 + 2 + +. 4. 5; this we only need to maintain a prefix and on it.
**! ! ! ! ! More importantly, remember the last added mod modulo again! ! ! ! ! ** Do not ask me why so excited. . . .

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n;
const ll mod=1e9+7;
char b[100100];
ll sc[100100];// 存1的数量的前缀和 
ll sm[100100];// 存 值为1的坐标的前缀和 

void add(ll x,ll k)
{
	ll f=1;
	if(k<0) f=-1;//如果 k 小于 0的时候表示把1变成0需要减  
	for(ll i=x;i<=n;i+=(i&-i))
	{
		sc[i]+=f;
		sm[i]=(sm[i]+k)%mod;
	}
	return;
}
ll sum_c(ll x)//求前面 1 数量的前缀和 
{
	ll ans=0;
	for(ll i=x;i;i-=(i&-i))
	{
		ans=ans+sc[i];
	}
	return ans%mod;
}
ll sum_s(ll x)//求 值为1的坐标的前缀和
{
	ll ans=0;
	for(ll i=x;i;i-=(i&-i))
	{
		ans=(ans+sm[i])%mod;
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	scanf("%s",b+1);
	ll ans=0;
	for(ll i=1;i<=n;i++)
	{
		if(b[i]=='1')
		{
			add(i,i);//更新两个前缀和 
			//根据公式设刚开始是一个空的子串开始加 
			ans=(ans+sum_c(i-1)*i-sum_s(i-1))%mod;
			//因为刚开始是从前到后的所以不用管 i 后面的位置 
		}
	}
	cout<<ans<<"\n";
	ll m;
	cin>>m;
	ll x,y;
	while(m--)
	{
		cin>>x>>y;
		if(x==1)
		{
			ll sum_p=sum_s(y);//求出前面值为1的坐标的前缀合 
			ll sum_n=sum_s(n)-sum_p;//求后面值为1的坐标的前缀和 
			
			ll suc_p=sum_c(y);// 求前面 1 一共有多少个1 
			ll suc_n=sum_c(n)-suc_p;// 求后面一共有多少个1 
			//根据推出来的公式操作 
			ans=(ans+y*suc_p%mod-sum_p+sum_n-suc_n*y%mod)%mod;
			ans=(ans+mod)%mod;//这里一定记得再次取模!!!!!! 
			add(y,y);//更新 
			cout<<ans<<"\n";
		}
		else{
			add(y,-y);//这里先更新是为了更新后这个位置刚好是0;
					  //对求后面的值不影响	 
			ll sum_p=sum_s(y);
			ll sum_n=sum_s(n)-sum_p;
			
			ll suc_p=sum_c(y);
			ll suc_n=sum_c(n)-suc_p;//这是把1变成0所以要减 
			ans=(ans-(y*suc_p-sum_p+sum_n-suc_n*y)%mod+mod)%mod;
			ans=(ans+mod)%mod;
			cout<<ans<<"\n";
		}
	}
	return 0;
}
Published 49 original articles · won praise 14 · views 4335

Guess you like

Origin blog.csdn.net/qq_43750980/article/details/104227644
ii