HDU 5475 平衡树/线段树

题目意思百度上到处都是啊~


题目大意:

有一个特殊的计算器,初始值 X = 1。现在有两种操作:

1. 乘以 Y

2. 除以一个之前乘过的数。

每次操作之后,输出对 M 取余的值。



方法1(错误):

根据题目意思,用同余计算。

但是这里的要取余的数字是不是素数!所以这个方法不对

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <math.h>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::sort;
using std::min;
using std::max;
using std::vector;
#define LL long long

LL n, mod;
const int MAXN = 100000 + 1000;
LL a[MAXN];

LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    LL r=exgcd(b,a%b,x,y);
    LL t=x;
    x=y;
    y=t-a/b*y;
    return r;
}

/*
bool modular_linear_equation(LL a,LL b,LL n)
{
    LL x,y,x0,i;
    LL d=exgcd(a,n,x,y);
    if(b%d)
        return false;
    x0=x*(b/d)%n;   //特解
    cout<<"!"<<d<<endl;
    for(i=1;i<d;i++)
        printf("%d\n",(x0+i*(n/d))%n);
    return true;
}
*/

LL  modular_linear_equation(LL a,LL b,LL n)
{
    LL x,y,x0,i;
    LL d=exgcd(a,n,x,y);
    if(b%d)
    {
    	while (1)
	{
		cout<<"!!"<<endl;
	}
    } //无解,但是这个题不可能的
    x0=x*(b/d)%n;   //特解
   // x0 = (x0 + n) % n;
    return x0;
}


int main()
{
	//cout<<modular_linear_equation(1, 2, 100);
	//return 0;
	//freopen("a.txt","w",stdout);
	int ttt;
	scanf("%d", &ttt);
	for (int j = 1; j <= ttt; ++ j)
	{
		printf("Case #%d:\n", j);	
		scanf("%I64d%I64d", &n, &mod);
		LL now = 1LL;
		int tot = 0; //存在多少个整数倍
		for (int i = 1; i <= n ; ++ i) //要修改
		{
			LL flag;
			scanf("%I64d%I64d", &flag, &a[i]);
			if (now == 0 && tot == 0)	now = mod;
			if (flag == 1LL)	
			{
				if (a[i] % mod == 0)	++tot;
				else now = (now * a[i]) % mod;
				if (now == 0)	tot ++;
			}
			if (flag == 2LL)
			{
				LL A = a[a[i]];
				if (A % mod == 0) 
				{
					--tot;
					goto xxx;//如果去掉了一个整数倍的,不用计算
				}
				if (mod % A == 0) --tot;
				LL B = now;
				LL willnow = modular_linear_equation(A, B, mod);
				now = willnow % mod;
			}
			xxx:;
			now = now % mod;
			if (tot) printf("0\n");
			else printf("%I64d\n", now);
		}
	}
	return 0;
}



方法2:线段树

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using std::cin;
using std::cout;
using std::endl;
using std::min;
using std::max;

#define LL long long
int n;
LL mod;

struct node
{
	int L, R;
	LL key;
	int ls,rs;
	void clear()
	{
		key = 1;
	}
	node():key(1),L(-1),R(-1), ls(-1), rs(-1){}
}t[100000 * 2 + 200];
int tail=0;

void make_tree(int now, int ll, int RR)
{
	t[now].L = ll;
	t[now].R = RR;
	t[now].key = 1; //全部都为1
	if (ll == RR)	return;
	int mid = (ll + RR) / 2;
	t[now].ls = ++ tail;
	make_tree(tail, ll, mid);
	t[now].rs = ++ tail;
	make_tree(tail, mid + 1, RR);
}

LL change_tree(int now, int k, LL p) //在k位置改为p
{
	if (t[now].L == k && t[now].R == k)
	{
		t[now].key = p;
		return p;
	}
	int mid = (t[now].L + t[now].R) / 2;
	if (k <= mid)	change_tree(t[now].ls, k, p); 
	if (mid < k)	change_tree(t[now].rs, k, p); 
	LL a = t[t[now].ls].key;
	LL b = t[t[now].rs].key;
	t[now].key = (a * b) % mod;
	return (a * b) % mod;
}

int main()
{
	int tt, tmp;
	scanf("%d", &tt);
	make_tree(0, 1, 100001);
	for (int ttt = 1; ttt <= tt; ++ ttt)
	{
		for (int i = 0; i != tail + 10; ++ i) t[i].clear();//tree init
		printf("Case #%d:\n", ttt);
		scanf("%d%I64d", &n, &mod);
		for (int i = 1; i <= n; ++ i)
		{
			int flag;	
			LL num;
			scanf("%d%I64d", &flag, &num);
			if (flag == 1)	cout << change_tree(0, i, num);
			else cout << change_tree(0, num, 1) ;
			cout << endl;
		}
	}
	return 0;
}



方法3:平衡树。

类似平衡树维护总和的方法,来维护一颗平衡树的积。

比赛时候一个int没改为LL所以错了,这让我十分十分的忧伤!不然就区域赛出线了,哎。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <math.h>
#include <vector>
#include <map>
#include <stack>
#include <algorithm>
#include <vector>
#pragma comment(linker, "/STACK:102400000,102400000")  
using std::cin;
using std::cout;
using std::endl;
using std::sort;
using std::min;
using std::max;
using std::vector;
#define LL long long



LL n, mod;
const int MAXN = 200010;


struct Size_Balabced_Tree{
	int left[MAXN],right[MAXN],s[MAXN],root,tt;
	LL w[MAXN], key[MAXN];
 	void clear(){
		memset(left,0,sizeof(left));
		memset(right,0,sizeof(right));
		memset(s,0,sizeof(s));
		for (int i = 0; i != MAXN; ++ i)    w[i] = key[i] = 1;
		root=tt=0;
	}
	void gr(int &t){
		int k=left[t];
		left[t]=right[k];
		right[k]=t;
		s[k]=s[t];
		w[k] = w[t]; //
		s[t]=s[left[t]]+s[right[t]]+1;
		w[t] = ((w[left[t]] * w[right[t]])%mod * key[t]) % mod;//
		t=k;
	}
	void gl(int &t){
		int k=right[t];
		right[t]=left[k];
		left[k]=t;
		s[k]=s[t];
		s[t]=s[left[t]]+s[right[t]]+1;
		w[k] = w[t];//
		w[t] =(( w[left[t]] * w[right[t]]) % mod * key[t]) % mod;
		t=k;
	}
 void _insert(int &t,LL v){
  if (!t){
   t=++tt;
   key[t]=v;
   w[t] = v; //
   s[t]=1;
   return ;
  }
  ++s[t];
  w[t] = (w[t] * v) % mod;
  if (v<key[t]){
   _insert(left[t],v);
   if (s[left[left[t]]]>s[right[t]]) gr(t);

  }
  else{
   _insert(right[t],v);
   if (s[right[right[t]]]>s[left[t]]) gl(t);
  }
  w[t] = ((w[left[t]] * w[right[t]] % mod ) * key[t] ) % mod;
 }
 LL _dele(int &t,LL v){
 LL ans;
  --s[t];
  if (v==key[t] || v<key[t] && !left[t] || v>key[t] && !right[t])
  {
       ans=key[t];
         if (!left[t] || !right[t]) t=left[t]+right[t];
         else key[t]=_dele(left[t],v+1);
  }
  else
      if (v<key[t]) ans=_dele(left[t],v);
      else ans=_dele(right[t],v);
  w[t] = ((w[left[t]] * w[right[t]] % mod)* key[t]) % mod;//
  return ans;
 }
 bool _find(int &t,LL v){
  if (!t) return false;
  if (key[t]==v) return true;
  if (v<key[t]) return _find(left[t],v);
  else return _find(right[t],v);
 }
 LL _rank(int &t,LL v){   //查v的排名
  if (t==0) return 1;
  if (v<=key[t]) return _rank(left[t],v);
  else return s[left[t]]+1+ _rank(right[t],v);
 }
 LL _selectmintomax(int &t,LL k){  //查第k名 (从小到大)
  if (k==s[left[t]]+1) return key[t];
  if (k<=s[left[t]]) return _selectmintomax(left[t],k);
  else return _selectmintomax(right[t],k-1-s[left[t]]);
 }
 int _selectmaxtomin(int &t,int k){ //查第k名 从大到小排名
  if (k==s[right[t]]+1) return key[t];
  if (k<=s[right[t]]) return _selectmaxtomin(right[t],k);
  else return _selectmaxtomin(left[t],k-1-s[right[t]]);
 }
 int _pred(int &t,int v){  //找比v小的最大的 找不到就返回自己
 int ans;
  if (t==0) return v;
  if (v<=key[t]) ans=_pred(left[t],v);
  else{
   ans=_pred(right[t],v);
   if (ans==v) ans=key[t];
  }
  return ans;
 }
 int _succ(int &t,int v){ //找比v大的最小的数字 找不到返回自己
 int ans;
  if (t==0) return v;
  if (v>=key[t]) ans=_succ(right[t],v);
  else {
   ans=_succ(left[t],v);
   if (ans==v) ans=key[t];
  }
  return ans;
 }
 void insert(int k){   //插入K
  _insert(root,k);
 }
 bool find(int k){     //查找K,返回ture false
  return _find(root,k);
 }
 int dele(int k){     //删除K,如果有就删掉,没有就删掉遍历到的最后一个数字,并且返回这个数字(你可以重新插入)
  return _dele(root,k);
 }
 int rank(int k){    //查找K在树种的排名,从小到大排名
  return _rank(root,k);
 }
 int selectmintomax(int k){  //插找第K小元素
  return _selectmintomax(root,k);
 }
 int selectmaxtomin(int k){  //查找第K大元素
  return _selectmaxtomin(root,k);
 }
 int pred(int k){  //找比K小的最大的数字
  return _pred(root,k);
 }
 int succ(int k){  //找比K大的最小的数字
  return _succ(root,k);
 }
}SBT;
LL a[MAXN];


void pg()
{
    cout<<"root="<<SBT.root<<endl;
    for (int i = 0; i <= 15; ++ i)
    {
        cout <<" i="<<i<<" left="<< SBT.left[i] <<" right=" <<SBT.right[i] <<" s=" << SBT.s[i] << " key="<< SBT.key[i]<<" w="<<SBT.w[i]<<endl;
    }
}

int main()
{
//	int size = 256 << 20; // 256MB
    //char *p = (char*)malloc(size) + size;
 //   __asm__("movl %0, %%esp\n" :: "r"(p));
    //freopen("a.txt","w",stdout);
    int ttt;
    scanf("%d", &ttt);
    for (int j = 1; j <= ttt; ++ j)
    {
        printf("Case #%d:\n", j);    
        SBT.clear();
        SBT.insert(1);
        scanf("%I64d%I64d", &n, &mod);
        for (int i = 1; i <= n ; ++ i) //要修改
        {
            LL flag;
            scanf("%I64d%I64d", &flag, &a[i]);
            if (flag == 1)    SBT.insert(a[i]);
            if (flag == 2)    SBT.dele(a[a[i]]);
            printf("%I64d\n", (SBT.w[SBT.root]) % mod);
        }
        //pg();
    }
    return 0;
}

你可能感兴趣的:(线段树,平衡树)